2014-01-30 21 views
2

當一個對象需要同步,IDE會抱怨,如果它沒有設置非最終(因爲它引用不是永久):當一個鎖持有一個非最終對象時,該對象的引用是否仍然被另一個線程改變?

private static Object myTable; 
.... 

synchronized(myTable){   //IDE complains! 
    //access myTable here... 
} 

我們都知道,IDE會阻止另一個線程進入如果持有鎖的線程更改非最終對象的引用,則保護塊。

但是,當線程A持有同一個對象的鎖時,另一個線程B是否可以更改同步對象的引用?

回答

5

但是同步對象的引用是否也可以被另一個線程B改變,而線程A是否擁有同一個對象的鎖?

如果你的意思是「可能另一個線程改變myTable變量的值,得到的回答是‘絕對’......假設有這將允許一個代碼路徑,這是一個私有變量,所以你應該能夠找出所有可以更改值的代碼。

持有鎖只是停止另一個線程從獲取同一個鎖,它並沒有什麼代碼可以訪問自己的變量,任何影響。

作爲一個側面說明,區分對象變量,以及變量的值(它是一個引用,而不是一個對象)。所以不存在「最終對象」 - 只有變量(以及類和方法)纔是最終的。同樣,沒有「同步對象」這樣的東西,並且不能更改「對象的引用」 - 您可以更改變量的值,以便它是對不同對象的引用。在腦海中清晰地區分這些區別可能會幫助您在思考此處發生的情況。

+0

是的,這就是我的意思,可能標題應該是:*「當一個鎖持有非最終變量的對象時,該變量的值是否可以被另一個線程改變?」*這一切都是爲了找到正確的話,對吧? ;) – Marcus

+0

@馬庫斯:呃,那還不是我怎麼說的。你用來獲取鎖的引用*發生了*來自一個變量,但那只是因爲它是那個時刻變量的值。可能有其他變量具有相同的參考。 –

+0

所以另一個嘗試:*「當一個鎖持有從非最終變量獲取的對象時,該變量的值是否仍然被另一個線程改變?」* – Marcus

1

是的,它可以。無論對象是在受保護的塊內部還是外部,所有非最終變量/字段都可以隨時更改它們的值/對象的引用。因此,你總是需要組合使用第三方鎖與非最終字段:

private static Object myTable; 
private final static Object LOCK; 
.... 

synchronized(LOCK){ 
    //access myTable here... 
} 

只有一個字段設置爲final將防止任何鎖定任何參考changements。可以說後者是一種錯誤的Java行爲,通過調用synchronized也可以鎖定引用。但這就是它需要的方式,否則代碼將變得無法維護。那麼,至少需要一些新的領域,如private guardable Object o;爲此目的需要。 ;)

編輯:

這裏的一類測試中的測試案例(注意,構造負載線非常難以預測,因此,因此等待(1000)...但是,這只是意味着是一個測試,通常你不應該在構造函數啓動線程的話):

private volatile boolean first = true; 
private TestObject testObject; 
private Thread thread;  

public Test(){ 
    testObject = new TestObject(); 
    thread = new Thread(this); 
    thread.start(); 
    try { 
     synchronized(this){ 
      wait(1000); 
     } 
    } catch (InterruptedException ex) {} 
    first = false; 
    thread = new Thread(this); 
    thread.start(); 
} 

public void run() { 
    System.out.println("First: "+testObject.toString()); 
    if(!first){ 
     testObject = new TestObject(); 
    } 
    synchronized(testObject){ 
     System.out.println("Second: "+testObject.toString()+" locked!"); 
     try { 
      synchronized(this){ 
       System.out.println("Thread "+thread+" waiting!"); 
       wait(); 
      } 
     } catch (InterruptedException ex) {} 
    } 
} 

public static void main(String[] args) { 
    Test test = new Test(); 
} 

的結果是:

First: [email protected] 
Second: [email protected] locked! 
Thread Thread[Thread-0,5,main] waiting! 
First: [email protected] 
Second: [email protected] locked! 
Thread Thread[Thread-1,5,main] waiting! 

您可以在第5行看到有沒有預防鎖的參考變更。那麼測試改爲:

private volatile boolean first = true; 
private TestObject testObject; 
private Thread thread; 
private final Object LOCK = new Object(); 
... 

public void run() { 
    System.out.println("First: "+testObject.toString()); 
    if(!first){ 
     testObject = new TestObject(); 
    } 
    synchronized(LOCK){ 
    ... 

屈服這樣的結果:

First: [email protected] 
Second: [email protected] locked! 
Thread Thread[Thread-0,5,main] waiting! 
First: [email protected] 

這裏第二個線程等待獲取鎖,而這正是我們想要的。

相關問題