1. 程式人生 > >java synchronized到底鎖住的是什麼

java synchronized到底鎖住的是什麼

  剛學java的時候,只知道synchronized一個執行緒鎖,能夠鎖住程式碼,但是它真的能像我想的那樣,能夠鎖住程式碼嗎?
  在討論之前先看一下專案中常見關於synchronized的用法:
 public synchronized  void syncCurrentObject() {
             System.out.println(Thread.currentThread().getName()+"..start.."+"-----"+System.currentTimeMillis());  
                try {  
                    Thread.sleep
(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"..end.."+"-----"+System.currentTimeMillis()); }

這樣能否在多個執行緒訪問時候,保證只有一個執行緒進入方法,其它執行緒阻塞嗎?
我用執行緒池建立三個執行緒容量,分別啟動五個執行緒:

    public static void syncCurrentObjectTest() {
        ExecutorService exec = Executors.newFixedThreadPool(3);

    //  final GenerateCode gCode = new GenerateCode();

        for (int i = 0; i < 5; i++) {
            exec.execute(new Runnable() {
                @Override
                public
void run() { GenerateCode gCode = new GenerateCode(); gCode.syncCurrentObject(); } }); } exec.shutdown(); }

執行效果截圖:
這裡寫圖片描述
根據截圖的輸入日誌說明將synchronized加在方法上並不能讓執行緒安全,而是多個執行緒並行執行。比如:執行緒3並沒有等執行緒1執行完成後再執行,而是執行緒1休眠的時候,執行緒3直接獲得鎖,進行執行。那麼在原有的實現上,如果保證執行緒安全呢?
解決思路:在多個執行緒呼叫synchronized修飾的方法時,呼叫synchronized方法是同一個物件。
具體解決方案是:將GenerateCode 物件建立一次(寫成單例更好),然後呼叫synchronized修飾方法。
具體修改截圖如下:
這裡寫圖片描述
為什麼這樣改就可以呢?原理是因為對於成員方法,synchronized只能鎖住當前物件的執行緒,其它物件的執行緒無法鎖住。而且synchronized放在方法和在方法內synchronize(this)是等價的。都只能鎖住當前物件。
但是如果想鎖住不同物件的多個執行緒,該怎麼做呢?示例程式碼如下:

    //直接在靜態方法上加synchronized  執行緒安全
    public synchronized static void syncStatic() {
        //dosomething..
    }  

    //在靜態方法上synchronized當前類 執行緒安全
    public  static void syncCurrentClass() {

            synchronized(GenerateCode.class){
                  //dosomething..
            }
        }

    //在成員方法上synchronized當前類 執行緒安全
    public   void syncCurrentObjectByThisClass() {
        synchronized(GenerateCode.class){
           //dosomething..
        }
    }

用synchronized鎖住當前類位元組碼,當前類中總是隻有一個執行緒可以進入執行,其它執行緒進入阻塞。

總結:synchronized可以鎖當前物件,也可以鎖類。
synchronized鎖住當前物件的寫法:
public synchronized void a(){
}

public void ab(){
synchronized (this){
}
}

synchronized鎖住當前類的寫法:
public synchronized static void a(){
}
public static void a(){
synchronized (類名){
}
}
public void ab(){
synchronized (類名){
}
}
我的理解是:當synchronized作用在物件時候,同一個物件中的執行緒是互斥的,只有一個執行緒執行完成後,另外一個執行緒才能獲得物件鎖得到執行。如果不是同一個物件,則不會產生互斥
當synchronized作用在類時,對於同一個jvm中不同物件的多個執行緒呼叫同一個synchronized修飾的方法都是互斥的,因為一個jvm只會產生一個class檔案。

拓展:
1、如果想讓執行緒互斥,synchronized方法是否存在效率問題?
理論應該是存在效率問題的,因為每個物件都有一個物件鎖,當一個執行緒拿到鎖後,其它執行緒必須阻塞。(未寫程式碼測試)

2、如果是分散式的系統,使用synchronized無效了,因為synchronized最多隻能鎖住當前JVM的執行緒,對於其它server的執行緒無能為力。那麼怎麼處理呢?
查了些資料,網上說可以用zookeeper+其它元件完成分散式鎖或者樂觀鎖。由於沒有具體實踐過,只是看了幾篇文章,沒有發言權,所以感興趣的朋友可以自行搜尋 java+分散式鎖