[英]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.