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+分布式鎖

完整測試demo源代碼:http://download.csdn.net/download/zl544434558/9495663


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM