2009-07-15 6 views
20

Gibt es Parallelitätsprobleme mit einem Thread, der von einem Index eines Arrays liest, während ein anderer Thread in einen anderen Index des Arrays schreibt, solange die Indizes unterschiedlich sind?java array thread-safety

z.B. (In diesem Beispiel nicht unbedingt für wirkliche Verwendung empfohlen, nur um meinen Standpunkt zu erläutern)

class Test1 
{ 
    static final private int N = 4096; 
    final private int[] x = new int[N]; 
    final private AtomicInteger nwritten = new AtomicInteger(0); 
    // invariant: 
    // all values x[i] where 0 <= i < nwritten.get() are immutable 

    // read() is not synchronized since we want it to be fast 
    int read(int index) { 
     if (index >= nwritten.get()) 
      throw new IllegalArgumentException(); 
     return x[index]; 
    } 
    // write() is synchronized to handle multiple writers 
    // (using compare-and-set techniques to avoid blocking algorithms 
    // is nontrivial) 
    synchronized void write(int x_i) { 
     int index = nwriting.get(); 
     if (index >= N) 
      throw SomeExceptionThatIndicatesArrayIsFull(); 
     x[index] = x_i; 
     // from this point forward, x[index] is fixed in stone 
     nwriting.set(index+1); 
    }  
} 

edit: dieses Beispiel critiquing ist nicht meine Frage, ich will wirklich nur, wenn Array Zugriff auf einen Index kennen, gleichzeitig Zugriff auf einen anderen Index, wirft Nebenläufigkeit Probleme, konnte nicht an ein einfaches Beispiel denken.

Antwort

12

Während Sie nicht einen ungültigen Zustand erhalten, indem Arrays zu ändern Wie Sie erwähnen, haben Sie das gleiche Problem, wenn zwei Threads eine nichtflüchtige ganze Zahl ohne Synchronisation anzeigen (siehe Abschnitt im Java-Tutorial unter Memory Consistency Errors). Grundsätzlich besteht das Problem darin, dass Thread 1 einen Wert in das Leerzeichen i schreiben kann, aber es gibt keine Garantie, wann (oder falls) Thread 2 die Änderung sehen wird.Die Klasse java.util.concurrent.atomic.AtomicIntegerArray erledigt, was Sie tun möchten.

+0

danke ... drat, ich wollte ein byte [] -Array verwenden und es sieht aus als gäbe es kein Atomic-Tier .... Ich denke, ich werde nur synchronisierte Methoden verwenden und es einfach halten. –

+2

Wenn Sie viel mehr Lese- als Schreibvorgänge haben, sollten Sie sich vielleicht java.util.concurrent.locks.ReadWriteLock ansehen –

+0

huh, interesting ... –

4

Das Beispiel hat eine Menge Zeug, das sich von der Prosa-Frage unterscheidet.

Die Antwort auf diese Frage ist, dass auf verschiedene Elemente eines Arrays unabhängig zugegriffen wird, so dass Sie keine Synchronisation benötigen, wenn zwei Threads verschiedene Elemente ändern. Das Speichermodell von Java gibt jedoch keine (mir bekannten) Garantien dafür aus, dass ein von einem Thread geschriebener Wert für einen anderen Thread sichtbar ist, es sei denn, Sie synchronisieren den Zugriff.

Je nachdem, was Sie wirklich versuchen, ist es wahrscheinlich, dass java.util.concurrent bereits eine Klasse hat, die es für Sie tun wird. Und wenn nicht, empfehle ich immer noch, den Quellcode für ConcurrentHashMap zu betrachten, da Ihr Code anscheinend dasselbe tut, was er tut, um die Hash-Tabelle zu verwalten.

1

Ich bin nicht wirklich sicher, ob die Synchronisierung nur die write Methode, während die read Methode unsynchronisiert funktionieren würde. Nicht wirklich, was sind die Konsequenzen, aber zumindest könnte es dazu führen, dass read Methode einige Werte zurückgibt, die gerade von write überschrieben wurde.

1

Ja, da ein fehlerhaftes Cache-Interleaving in einer Multi-CPU/Core-Umgebung noch auftreten kann. Es gibt mehrere Möglichkeiten, es zu vermeiden:

  • Verwenden Sie die Unsafe Sun-private Bibliothek atomar ein Element in einem Array gesetzt (oder die jsr166y Funktion hinzugefügt, in Java7
  • Verwenden AtomicXYZ [] Array
  • Use custom Objekt mit einem flüchtigen Feld und haben eine Reihe von diesem Objekt.
  • Verwenden Sie die ParallelArray von jsr166y Addendum statt in Ihrem Algorithmus
1

Da read() nicht synchronisiert können Sie die folgenden scen haben ario:

Thread A enters write() method 
Thread A writes to nwriting = 0; 
Thread B reads from nwriting =0; 
Thread A increments nwriting. nwriting=1 
Thread A exits write(); 

Da Sie sicherstellen wollen, dass Ihre variablen Adressen nie Konflikt, was so etwas wie (Diskontierung Array-Index Ausgaben):

int i; 
synchronized int curr(){ return i; } 
synchronized int next(){ return ++i;} 

int read() { 
     return values[curr()]; 
    } 

void write(int x){ 
    values[next()]=x; 
} 
+0

danke, aber nicht meine Frage & Ihr Szenario kann nicht passieren (Schritte 2 und 3 würden nie auftreten) –