java容許多線程併發控制,當多個線程同時操做一個可共享的資源變量時,將會致使數據不許確,相互之間產生衝突,所以加入同步鎖以免該線程沒有完成操做以前,被其餘線程調用,從而保證數據的惟一性和準確性。 1.同步方法,即爲synchronized關鍵字修飾的方法。 public sunchronized void save(){} 例如該方法,因爲java的每個內置對象都有一個內置鎖,當用此關鍵字修飾方法是,內置鎖會保護整個方法。在調用該方法前,須要得到內置鎖,不然就處於阻塞狀態。 注意:synchronized關鍵字也能夠修飾靜態方法,此時若是調用靜態方法,將會鎖住整個類。java
2.同步代碼塊,被關鍵字修飾的語句塊會自動被加上內置鎖,從而實現同步 synchronized(object){} 同步代碼塊和同步方法不一樣,同步代碼塊必須有鎖。 注意:同步是一種高開銷的操做,所以應該儘可能減小同步的內筒,一般咱們優先選擇同步代碼塊來同步關鍵代碼便可。面試
3.使用volatile關鍵字修飾變量來實現線程同步多線程
peivate volatile int account = 100; a.volatile關鍵字爲域變量的訪問提供了一種免鎖機制 b.使用volatile修飾域至關於告訴虛擬機該域有可能會被其餘線程更新,所以每次使用該域就要從新計算,而不是使用寄存器中的值。volatitle不會提供任何原子操做,他也不能用來修飾final類型的變量。併發
4.使用重入鎖實現線程同步 ReentrantLock類能夠重入,互斥,實現了Lock接口的鎖, 該類的經常使用方法 lock() 得到鎖 unlock(): 釋放鎖ide
class Bank { private int account = 100; //須要聲明這個鎖 private Lock lock = new ReentrantLock(); public int getAccount() { return account; } //這裏再也不須要synchronized public void save(int money) { lock.lock(); try{ account += money; }finally{ lock.unlock(); } } }
注:關於Lock對象和synchronized關鍵字的選擇:線程
a.最好兩個都不用,使用一種java.util.concurrent包提供的機制, 可以幫助用戶處理全部與鎖相關的代碼。 b.若是synchronized關鍵字能知足用戶的需求,就用synchronized,由於它能簡化代碼 c.若是須要更高級的功能,就用ReentrantLock類,此時要注意及時釋放鎖,不然會出現死鎖,一般在finally代碼釋放鎖
5.使用局部變量實現線程同步 若是使用ThreadLocal管理變量,則每個人使用該變量的線程都得到該變量的副本。 副本之間相互獨立,這樣每個線程均可以隨意修改本身的變量副本,而不會對其餘線程產生影響。 ThreadLocal 類的經常使用方法 ThreadLocal() : 建立一個線程本地變量code
get() : 返回此線程局部變量的當前線程副本中的值 initialValue() : 返回此線程局部變量的當前線程的"初始值" set(T value) : 將此線程局部變量的當前線程副本中的值設置爲value
public class Bank{ //使用ThreadLocal類管理共享變量account private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){ @Override protected Integer initialValue(){ return 100; } }; public void save(int money){ account.set(account.get()+money); } public int getAccount(){ return account.get(); } }
面試題:一個線程進入對象的synchronized方法A以後,其餘線程是否能夠進去此對象的synchronized的方法B? 回答:不能夠,所對象沒有釋放,其餘線程不能進入方法B。對象