2017-07-18 57 views
0
class C { 
    Object o; 
    public void set(Object o){ 
    if(this.o == null){ 
     this.o = o; 
    } 
    } 
    public Object get(){ 
    return o; 
    } 
} 

C c = new C(); 

C c = new C(); 

Thread#1 
Object o1 = c.get(); // 1 
Object o2 = c.get(); // 2 

Thread#2 
c.set(new Object()); 

難道o2 == null && o1 != null? 爲什麼?Java內存模型和併發讀取


要清楚我的意思是我編輯:

如果我們有以下的情況:,

C c = new C(); // it is given at beginning 
1) Object o2 = c.o; // o2 is null. This operation was **reordered** before O `o1 = c.o. The JVM can do it because JMM allows do it. 
2) c.o = new Object()` //Thread #2 was executed 
3) O o1 = c.o // o1 is not null while o2 is. 
+0

我不明白'get()'返回除'null'之外的任何東西是可能的。如果參數爲空,'o'永遠不會被初始化,'set()'只會修改'o' –

+0

不,因爲c1在c2之前被檢索到,並且在任何其他線程中沒有東西可以將其恢復爲空。然而,c2可能非空而c1爲空 – litelite

回答

2

這是不可能的,儘管事實上,你有一個數據競爭。

數據比賽是因爲你的獲取和設置圍繞o不同步,這意味着沒有之前發生順序與他們。您可以通過使兩種方法都是​​或使o易變或通過其他幾種方法來解決這個問題。

缺席同步時,JVM被允許通過其他線程所看到重新排序事件。從線程1的角度來看,您有以下事件(與方法,內聯爲簡單起見):

c.o = null; // initial value 
o1 = c.o; 
o2 = c.o; 
c.o = new Object(); // from Thread2 

幸運的是,有兩個限制,使這項工作:

  1. c.c = null之前發生的所有其他行動(見JLS 17.4.5)。
  2. 從給定的線程的角度來看,該線程上發生的行爲總是發生在它們出現在代碼(也JLS 17.4.5)的順序相同。所以對於Thread1,o1 = c.o發生在o2 = c.o之前。 (線程2將必須看到的順序讀取那些... ...但它永遠不會看到o1o2可言,所以沒有問題存在。)

其中第一個手段,我們不能採取c.o = null行動並在c.c = new Object()之後訂購。第二種方法意味着您在帖子底部提到的重新排序是不允許的,從Thread1的角度來看(當然,Thread1是唯一能夠看到o1或o2的線索)。

結合這兩個限制,我們可以看到,如果Thread1曾經看到c.o是非空的,那麼它將永遠不會看到它再次恢復爲空。如果o1非空,那麼必須是。

請注意,這是非常善變。例如,讓我們說,而不是僅僅設定c.o一次,線程2設置了兩遍:

c.set("one"); 
c.set("two"); 

在這種情況下,它可以看到o1是「兩」,而o2是「一」。這是因爲操作有:

c.o = null; // initial value 
o1 = c.o; 
o2 = c.o; 
c.c = "one"; // from Thread2 
c.c = "two"; // from Thread2 

的JVM可以重新排序從線程2項目但它認爲合適的,只要他們不認爲c.c = null面前。具體而言,這是有效的:

c.o = null; // initial value 
c.c = "two"; // from Thread2 
o1 = c.o; 
c.c = "one"; // from Thread2 
o2 = c.o; 

刪除數據的比賽,通過同步獲取並設置到o,將解決這個問題。

+0

我編輯我的帖子。 – Gilgamesz

+0

@Gilgamesz @Gilgamesz有趣的是,你編輯它,但仍然沒有解決'get()'鍵入返回Object的事實,但是當你調用它時,你嘗試將它分配給C.我誤解了它應該是'對象c1 = c.get()'? – yshavit

+0

你對,我編輯過。 – Gilgamesz