[Java]同步鎖synchronized
在多執行緒操作資料時需要考慮使用synchronized關鍵詞修飾屬性或方法,同步鎖synchronized大致可分為兩類:物件鎖、全域性鎖。在分析同步鎖程式碼時需要關心兩個問題:鎖的物件是誰、誰持有鎖。
①物件鎖:
當一個執行緒訪問物件object的一個synchronized(this)同步程式碼塊或synchronized修飾的例項方法時,其他執行緒對該object中所有其它synchronized(this)同步程式碼塊或synchronized修飾的例項方法的訪問將被阻塞。
public class Demo { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); for(int i = 0;i < 3;i++) { Thread t = new Thread(myRunnable); t.start(); } } } class MyRunnable implements Runnable{ static int i; @Override public void run() { add(); } synchronized void add() { System.out.println(Thread.currentThread().getName()+"開始,i = "+i); i++; System.out.println(Thread.currentThread().getName()+"結束,i = "+i); } }
輸出結果:
在上面的例子中,synchronized 修飾例項方法,鎖的物件是myRunnable,持有鎖的為當前執行該方法的執行緒。迴圈建立並啟動的三個執行緒都呼叫myRunnable物件的同步add()方法,當其中某個執行緒執行add()方法時需要先獲得myRunnable物件的鎖,若物件鎖被其他執行緒佔用,該執行緒將阻塞在此,等待鎖的獲得。
②全域性鎖
當一個執行緒訪問類的一個synchronized(類名.class)同步程式碼塊或synchronized修飾的類方法時,其他執行緒對該類中所有其它synchronized(類名.class)同步程式碼塊或synchronized修飾的類方法的訪問將被阻塞。
public class Demo { public static void main(String[] args) { for(int i = 0;i < 3;i++) { Thread t = new Thread() { @Override public void run() { Sync.add(); } }; t.start(); } } } class Sync{ static int i; synchronized static void add() { System.out.println(Thread.currentThread().getName()+"開始,i = "+i); i++; System.out.println(Thread.currentThread().getName()+"結束,i = "+i); } }
輸出結果:
在上面的例子中,synchronized 修飾類方法,鎖的物件是Sync.class,持有鎖的為當前執行該方法的執行緒。迴圈建立並啟動的三個執行緒都呼叫Sync類的靜態方法add(),當其中某個執行緒執行add()方法時需要先獲得Sync類的鎖,若物件鎖被其他執行緒佔用,該執行緒將阻塞在此,等待鎖的獲得。
總結:
1.使用synchronized物件鎖時,執行緒需要拿到的是該物件的鎖,否則將無法操作該物件中所有帶有物件鎖的屬性和方法。
2.使用全域性鎖時,需要拿到的是類檔案的鎖,否則將無法操作該類所有帶全域性鎖的屬性和方法。