是的,它可以。無論對象是在受保護的塊內部還是外部,所有非最終變量/字段都可以隨時更改它們的值/對象的引用。因此,你總是需要組合使用第三方鎖與非最終字段:
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]
這裏第二個線程等待獲取鎖,而這正是我們想要的。
是的,這就是我的意思,可能標題應該是:*「當一個鎖持有非最終變量的對象時,該變量的值是否可以被另一個線程改變?」*這一切都是爲了找到正確的話,對吧? ;) – Marcus
@馬庫斯:呃,那還不是我怎麼說的。你用來獲取鎖的引用*發生了*來自一個變量,但那只是因爲它是那個時刻變量的值。可能有其他變量具有相同的參考。 –
所以另一個嘗試:*「當一個鎖持有從非最終變量獲取的對象時,該變量的值是否仍然被另一個線程改變?」* – Marcus