2017-08-02 41 views
-3

我知道這顯然是一種競爭條件。但是可能發生的事情是什麼?在Java競爭條件下可能發生的最壞情況是什麼?

class Blah { 
    List<String> stuff; 
    public List<String> getStuff() { 
     return stuff 
    } 
    public void setStuff(List<String> newValue) { 
     this.stuff = newValue 
    } 
} 

b = new Blah(); 
// Thread one 
b.setStuff(getListFromSomeNetworkResource()); 
for (String c : b.getStuff()) { 
    // Work with c 
} 


// Thread two 
b.setStuff(getListFromSomeNetworkResource()); 
for (String c : b.getStuff()) { 
    // Work with c 
} 
    可以這樣丟的RuntimeException
  1. 可以這段錯誤jvm?
  2. 可以這段錯誤的線程之一?
  3. 它取決於處理器。如果它是英特爾至強處理器呢?
  4. 這可以拋出一個NullPointer異常嗎?
  5. 線程2可以讀取線程1,反之亦然設置的內容如果函數實際返回不同的值

我理解,這是一個競爭條件,不會寫這樣的代碼。但我如何說服別人不要?

更新:

假設:

  1. getListFromSomeNetworkResource()總是返回一個新ArrayList。大小可能爲0或更多。
  2. getListFromSomeNetworkResource()是線程安全的。
+0

下載者,請發表評論 – balki

回答

0

可以拋出RuntimeException嗎?

沒有,如果getListFromSomeNetworkResource()是線程安全的,不會返回null

可以這段錯誤jvm?

可以這段錯誤的線程之一?

它取決於處理器。如果它是英特爾至強處理器呢?

可以這樣拋出一個空指針異常?

只有當getListFromSomeNetworkResource()可以返回null

線程2可以讀取線程1,反之亦然設置的內容如果函數實際返回不同的值

是的,這是可能發生的。

-1

的危險將是一個排序,例如:

  1. 主題之一:b.setStuff(getListFromSomeNetworkResource());
  2. 主題二:b.setStuff(getListFromSomeNetworkResource());
  3. 主題之一:b.stuff.iterator()(通過b.getStuff(),在循環開始)

在這種情況下,線程一個可能將遍歷線程兩個集合的列表。從線程2到線程1的這個發佈沒有任何同步 - 這是一場數據競賽。假設列表本身不是線程安全的,很多事情都可能發生。主要的問題是,由於數據競爭,列表的一些狀態對於線程可見而不是全部。

  • 它可能會拋出一些RuntimeException。例如,也許一個字段認爲該列表由於調整大小而具有n元素。但是來自調整大小的新數組並沒有結束,所以最終會出現ArrayIndexOutOfBoundsException
  • 由於許多原因,它可能會拋出NullPointerException;也許這是一個鏈表,並參考寫入一個沒能線程一個

它應該不會造成任何段錯誤:那些只能從錯誤來約在JVM,但從來沒有錯誤在你的代碼。

它可能取決於處理器,因爲處理器可能具有不同的處理方式,如將內存從一個CPU緩存刷新到另一個CPU緩存 - 這是不安全發佈可能導致您僅看到一些數據的原因之一一個線程從另一個線程寫道。有辦法強制這些緩存被刷新;在Java中指定它們的方式是通過各種數據同步機制(獲取鎖,使用易失性字段等)。

+0

>>線程一可能迭代線程兩組的列表 這真的有可能嗎?迭代器不是對象的本地對象,並且這兩個線程都有不同的對象? – balki

+0

儘管兩個線程共享相同的'b'實例,所以兩者都可以共享相同的'b.stuff'引用。迭代器確實是線程本地的,但其後備列表不是。在我上面的示例中,按照我的步驟排序,請考慮第三步中引用哪個對象'b.stuff'。 – yshavit

+0

哦,一個半月以後的驅動器downvote。這是新的。 :-)任何評論解釋的機會? – yshavit