簡體   English   中英

多個線程執行相同的方法(非同步)行為

[英]Multiple Threads executing same Method (Non Synchronized) behavior

我調用了一個從多個線程向列表添加項目的方法,該方法未同步

static List<String> list = new ArrayList<String>();

static void addItem(int itemNo){

    list.add("item "+itemNo);
}
public static void main(String[] args) {


    ExecutorService executor = Executors.newFixedThreadPool(4);
    for (int i = 0; i < 10; i++) 
    {
        int itemNo = i;
        Runnable task = () -> addItem(itemNo);
        executor.execute(task);
    }

    executor.shutdown();


    System.out.println(list);

}

每次執行此代碼時,打印列表的輸出都是隨機的

[null,項目1,項目4,項目5,項目6,項目7,項目8,項目9]

[項目1,null,項目2,項目4,項目5,項目3,項目6,項目7,項目8,項目9]

[項目1,項目2,項目3,項目4,項目5,項目6,項目7,項目8,項目9]

在第一和第二輸出中,有空項目,分別是第一輸出中的第一和第二中的第二。 而且列表的大小也不一樣。

根據我的理解,這些項目不會在多線程中按順序放置。 我不知道在添加數組時項目有時為空或被跳過

我想了解這種行為,為什么將空項目添加到數組以及為什么在未同步我的方法時跳過項目

您的寶貴答案對我有很大幫助,在此先感謝

由於添加項目不是原子操作,因此需要多項操作,例如增加大小並將值分配給數組位置。

在多線程競爭條件下,有時兩個線程可能同時增加,因此它只會增加一次,而不是增加兩次,因此最終大小小於10。

有時,兩個線程都將在分配值之前按順序遞增,因此將跳過一個位置,並且兩個線程都將分配給相同的位置,一個線程會覆蓋另一個線程的值,因此會出現空值和缺失值。

簡而言之,對對象(如ArrayList多線程使用將破壞列表。 永遠不要做。 為什么您看到自己的結果並不重要,只是不這樣做。

List.add(Object)函數不是原子的。 也就是說,如果多個線程嘗試將元素添加到同一列表中,則它們可能會相互干擾並破壞add函數的內部工作(調整內部數據結構的大小,計算列表中項目的位置,... )。 這可能會導致意外的輸出,甚至導致嚴重的問題(例如,在沒有正確同步的情況下使用HashMap跨線程使用-即使是只讀操作)。

如果您使用同步List

 static List<String> list = Collections.synchronizedList(new ArrayList<String>());

這將使list實例上的方法調用synchronized從而添加有效的原子操作。 進行此更改后,仍不會按順序添加項目,但至少可以確保正確添加所有項目。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM