Streams und fork-join bieten beide Funktionen zum Parallelisieren von Code, der auf Arrays zugreift. Zum Beispiel wird Arrays.parallelSetAll
weitgehend durch die folgende Zeile implementiert:Wie greifen Streams/fork-join auf Arrays sicher zu?
IntStream.range(0, array.length).parallel()
.forEach(i -> { array[i] = generator.applyAsLong(i); });
Auch die documentation von RecursiveAction
, einen Teil des Gabel-Join Framework enthält das folgende Beispiel:
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++];
}
}
Schließlich parallele Ströme erstellt aus Arrays greifen auf die Arrays in mehreren Threads zu (der Code ist zu komplex, um hier zusammengefasst zu werden).
Alle diese Beispiele scheinen aus Arrays zu lesen oder in sie zu schreiben, ohne Synchronisation oder andere Speicherbarrieren (soweit ich das beurteilen kann). Wie wir wissen, sind vollständig Ad-hoc-Multithread-Array-Zugriffe unsicher, da es keine Garantie gibt, dass ein Lesen ein Schreiben in einem anderen Thread widerspiegelt, es sei denn, es gibt eine Vor-Vor-Beziehung zwischen dem Lesen und dem Schreiben. Tatsächlich wurden die Klassen Atomic...Array
speziell erstellt, um dieses Problem zu beheben. Da jedoch jedes obige Beispiel in der Standardbibliothek oder in der zugehörigen Dokumentation enthalten ist, nehme ich an, dass sie korrekt sind.
Kann jemand bitte erklären, welcher Mechanismus die Sicherheit der Arrayzugriffe in diesen Beispielen garantiert?
Beachten Sie, dass zwei Threads nicht auf den _Same_Array-Einträge arbeiten; sie überschneiden sich nicht. –
@LouisWasserman Egal, wie sieht der Thread, der 'parallelSetAll' aufruft oder der' SortTask' aufruft, die darin gemachten Schreibvorgänge? –