早在總結一時,我就盡量的把synchronized的重點說的簡單:它就是配和對象的隱式鎖使用的,注意一定是對象的隱式鎖!那麼下面的 這個例子又怎麼解釋呢?
Java代碼
/**
* User: yanxuxin
* Date: Dec 17, 2009
* Time: 9:38:27 PM
*/
public class ImplicitLockSample {
public static void main(String[] args) {
final ImplicitLock sample = new ImplicitLock();
new Thread(new Runnable() {
public void run() {
// ImplicitLock.method1();
sample.method1();
}
}).start();
new Thread(new Runnable() {
public void run() {
sample.method2();
}
}).start();
}
}
class ImplicitLock {
public static synchronized void method1() {
System.out.println("method1 executing...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void method2() {
System.out.println("method2 executing...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
這裡ImplicitLock有兩個同步方法,一個是static的,一個是普通的。ImplicitLockSample是一個測試主程序,實例化一個 ImplicitLock對象,並且開啟兩個線程,每個線程分別調用對象的method1和method2方法。每個進入方法的線程都會強制休眠 3秒。那麼執 行的現象是什麼呢?
要知道答案有以下幾點要清楚:a.Class和Object的關系,b.static方法的含義,c.synchronized的機制,d.sleep的作用。清楚的知道 這些之後,一眼就能辨別method1和method2方法上的synchronized配和的是兩把不同的對象隱式鎖。答案也就清晰的知道這兩個線程執行的 打印語句根本就不會相差近3秒的等待,而是幾乎同時。下面我試著解釋一下。
Class是Object的子類,說明了Class是特殊的對象,它自然也有對象隱式鎖。static聲明方法意味著這個方法不依賴於類的實例,而是 可以理解成去掉了隱式參數this的,類對象的方法。synchronized是與對象隱式鎖綁定的,這代表了將其置於方法聲明上它將與方法的持有 對象綁定。所以method1的同步鎖是ImplicitLock類對象的隱式鎖,而method2的同步鎖是ImplicitLock實例對象的隱式鎖。 sleep雖然能讓 當前的線程休眠,但是它不會釋放持有的隱式鎖。這樣主程序執行是雖然用同一個實例讓兩個線程分別去調用兩個方法,但是它們之間並沒 有任何競爭鎖的關系,所以幾乎同時打印,不會有近3秒的間隔。把method1的調用改成已注釋的代碼將更容易理解。如果method1的 synchronized去掉,或者method2加上synchronized的聲明,那麼它們將競爭同一個隱式鎖。先獲得鎖的線程將在3秒後交出鎖,後面的線程 才能執行打印。
寫這篇補遺源自於對懶漢式單例的重新理解,之前對synchronized的機制不明了時,只知道使用synchronized關鍵字在static方法上聲 明就能保證單例的線程安全,但是確不知道那算是誤打誤撞的理解。構造這個驗證例子之前,static和synchronized的共同使用讓我對 synchronized隱式鎖有了更清晰的認識。所以打算再寫寫來分享這段體會。