簡體   English   中英

stream / fork-join如何通過線程安全地訪問數組?

[英]How do streams / fork-join access arrays thread-safely?

Streams和fork-join都提供了並行化訪問數組的代碼的功能。 例如, Arrays.parallelSetAll主要由以下行實現:

IntStream.range(0, array.length).parallel()
    .forEach(i -> { array[i] = generator.applyAsLong(i); });

此外, RecursiveAction文檔 ,fork-join框架的一部分,包含以下示例:

static class SortTask extends RecursiveAction {
    final long[] array; final int lo, hi;
    ...
    void merge(int lo, int mid, int hi) {
        long[] buf = Arrays.copyOfRange(array, lo, mid);
        for (int i = 0, j = lo, k = mid; i < buf.length; j++)
            array[j] = (k == hi || buf[i] < array[k]) ?
                buf[i++] : array[k++];
    }
}

最后,從數組創建的並行流以多個線程訪問數組(代碼太復雜,無法在此匯總)。

所有這些示例似乎都是對數組進行讀取或寫入,而沒有任何同步或其他內存障礙(據我所知)。 我們知道,完全臨時的多線程數組訪問是不安全的,因為不能保證讀取反映另一個線程中的寫入,除非讀取和寫入之間存在先發生關系。 事實上, Atomic...Array類是專門為解決這個問題而創建的。 但是,鑒於上面的每個例子都在標准庫或其文檔中,我認為它們是正確的。

在這些例子中,有人可以解釋一下哪種機制可以保證陣列訪問的安全性?

簡短的回答:分區。

JMM是根據對變量的訪問來定義的 變量包括靜態字段,實例字段和數組元素。 如果你安排你的程序,使得線程T0是訪問數組元素0的唯一線程,同樣T1是訪問數組元素1的唯一線程,那么這些元素中的每一個都是有效線程限制的,並且你有沒問題 - JMM程序訂單規則會照顧你。

並行流建立在這個原則之上。 每個任務都在處理數組的一部分,而其他任務正在處理。 然后我們要做的就是確保運行任務的線程可以看到數組的初始狀態,最終結果的使用者可以看到數組相應部分的as-modified-by-the-task視圖。 通過嵌入在並行流和FJ庫的實現中的同步動作,可以很容易地安排這些。

暫無
暫無

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

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