執行緒安全-鎖機制 synchronized用法同步方法
阿新 • • 發佈:2018-12-15
一個簡單的例子,10個人搶8張票,結果肯定是有2個人搶不到票的
public class Ticket { private static CountDownLatch ctl =new CountDownLatch(1); private ReentrantLock rentLock=new ReentrantLock(); Integer stock=8;//總票數 public void reduce(int num){ if((stock-num)>=0){ try { ctl.await();//模擬併發場景,相當於所用執行緒同時到達才會執行 } catch (Exception e) { e.printStackTrace(); } stock-=num; System.out.println(Thread.currentThread().getName()+ "成功賣出:"+num+"張,庫存剩餘:"+stock+"張"); }else { System.out.println(Thread.currentThread().getName()+ "失敗,庫存不足:"+num+"張,庫存剩餘:"+stock+"張"); } } public static void main(String[] args) throws InterruptedException { final Ticket ticket=new Ticket(); for (int i = 0; i <10; i++) { new Thread(new Runnable() { public void run() { ticket.reduce(1); #只有10個執行緒同時開啟時,才會執行該方法,因為reduce方法中呼叫了ctl.await方法 //ticket.reduceByLock(1); } }).start();; } Thread.sleep(1000); ctl.countDown(); //啟動一個執行緒,計數器減一 } }
執行結果: 出現的負數,這就是執行緒安全引起的,只要把Ticket 中的reduce 方法加上synchronized 修飾,就可以解決這個問題
一 同步方法 方法加用 synchronized 修飾
public synchronized void reduce(int num){ if((stock-num)>=0){ try { ctl.await();//模擬併發場景,相當於所用執行緒同時到達才會執行 } catch (Exception e) { e.printStackTrace(); } stock-=num; System.out.println(Thread.currentThread().getName()+ "成功賣出:"+num+"張,庫存剩餘:"+stock+"張"); }else { System.out.println(Thread.currentThread().getName()+ "失敗,庫存不足:"+num+"張,庫存剩餘:"+stock+"張"); } }
再次執行結果:
為什麼呢,因為加了synchronized 關鍵字後,會保證每次只會用一個執行緒去呼叫reduce這個方法,當一個執行緒1在執行這個方法的時候,會獲得鎖,其他執行緒阻塞等待,執行緒1執行完之後,釋放鎖,其他執行緒競爭鎖。得到鎖的執行緒執行reduce方法,其他執行緒阻塞等待,以此類推,直到10個執行緒都執行完
加在方法上的鎖(也叫同步方法),鎖的都是物件,例子中執行時鎖的就是這個 ticket 物件(也就是呼叫reduce這個方法的物件)
同步方法的缺點:因為鎖在方法上,導致了鎖的範圍過大,會使單個執行緒序列執行時間變長,其他執行緒等待時間變長;影響系統性能