2014-03-27 53 views
0

錯誤代碼同步塊如何工作?

public class Scheduler { 
private Object lock = new Object(); 

private int interval; 
private int period; 

public Scheduler(int interval , int period) { 
    this.interval = interval; 
    this.period = period; 
} 

public synchronized void setInterval(int interval) { 
    this.interval = interval; 
} 

public synchronized void setPeriod(int period) { 
     this.period = period; 
} 

public void updateScheduler(int interval , int period) { 
    synchronized(lock) { 
     setPeriod(period); 
     setInterval(interval); 
    } 
} 

} 

我有一些線程問題,在我的代碼找到那些,我在我的項目跑線程安全的Eclipse插件。

線程安全報告

  1. 在調度程序類

    錯誤描述

    爲了避免dataraces的

    混合同步,重要的是,那些同時訪問域始終得到守衛一個共同的鎖。如果每次訪問一個字段時都沒有保持相同的鎖對象,則可能會發生datarace。

固定碼

public class Scheduler { 
    private Object lock = new Object(); 

    private int interval; 
    private int period; 

    public Scheduler(int interval , int period) { 
     this.interval = interval; 
     this.period = period; 
    } 

    public void setInterval(int interval) { 
     synchronized(lock) { 
      this.interval = interval; 
     } 
    } 

    public void setPeriod(int period) { 
      synchronized(lock) { 
      this.period = period; 
      } 
    } 

    public void updateScheduler(int interval , int period) { 
     synchronized(lock) { 
      setPeriod(period); 
      setInterval(interval); 
     } 
    } 

    } 

我測試此代碼,它工作正常。我的問題是,我正在調用setPeriodsetInteval from updateScheduler。當updateScheduler被調用時,對象已被鎖定,那麼我打電話的setIntervalupdateScheduler鎖定沒有公佈。我期待的代碼將最終死鎖。但是,這不是爲什麼?

回答

3

只有一個監視器被鎖定在固定代碼(lock)中,所以死鎖是不可能的。

要修復原始代碼,您也可以同步updateScheduler方法,而不是使用lock對象。它會達到同樣的目的。

根據你的問題,Java鎖定是「reentrant」,這意味着,當一個「鎖定」的代碼段試圖再次「鎖定」它(即使用相同的顯示器)時,它理解它的相同的顯示器,因此不會阻止/等待它被解鎖。它知道它已經「擁有」它。合理?

3

Java Language Specification

線程t可以鎖定特定的監視器多次;每次解鎖都會反轉一次鎖定操作的效果。

因此,您可以爲同一個對象嵌套​​塊。

synchronized(lock) { 
    synchronized(lock) { 
     synchronized(lock) { 
      // ad nauseam and within method calls 
     } 
    } 
} 

這進一步說明在Java教程Intrisic Locks and Synchronization

回想一下,一個線程不能獲取由另一個線程擁有的鎖。 但是一個線程可以獲得它已經擁有的鎖。允許線程多次獲取同一個鎖使得可重入 同步。這描述了一種情況,其中同步代碼 直接或間接地調用也包含 同步代碼的方法,並且這兩組代碼使用相同的鎖。沒有 重入同步,同步代碼將不得不採取許多額外的預防措施,以避免讓線程導致自身阻塞。