2016-11-10 5 views
0

Ich habe zwei Threads, jeder hat seinen eigenen Zähler: Thread A hat counterA, Thread B hat counterB. Jeder Thread muss beide Counter verwenden: Thread A muss counterA und counterB verwenden, auch Thread B muss beides verwenden. Ich verwende AtomicInteger und teile die Zähler zwischen den beiden Threads, die ich ihnen als Argumente an die Threads übergebe und jeder Thread speichert die beiden Zähler in privaten Feldern.sichere Veröffentlichung, Argument übergeben

// ... 
AtomicInteger counterA = new AtomicInteger(0); 
AtomicInteger counterB = new AtomicInteger(0); 

Thread tA = new Thread(new RunnableA(counterA, counterB)); 
Thread tB = new Thread(new RunnableB(counterA, counterB)); 

// ... in the constructor of RunnableA ... 
RunnableA(AtomicInteger counterA, AtomicInteger counterB) { 
    this.counterA = counterA; 
    this.counterB = counterB; 
} 

//... 
// The same for RunnableB 

Ist das ein safe publishing der beiden Zähler? Safe-Publishing ist erforderlich, da eine Referenz auf ein Objekt nicht sicher genug ist, um das Objekt zwischen Threads zu teilen. Wie kann ich in diesem Fall eine sichere Veröffentlichung erreichen?

Vielen Dank im Voraus.

Antwort

1

Der Begriff "sichere Veröffentlichung" ist darauf nicht anwendbar. Bei der sicheren Veröffentlichung geht es um die Veröffentlichung des im Konstruktor erstellten Zustands. In Ihrem Beispiel wurden die AtomicInteger Objekte erstellt, bevor der Konstruktor aufgerufen wurde.

Wenn ein anderer Typ verwendet wurde, dies kann oder kann nicht sicher sein, je nachdem, ob und wie die counterA und counterB Variablen veröffentlicht werden. Mit Zählern, die als AtomicInteger Objekte implementiert sind, müssen Sie sich jedoch keine Gedanken über die Veröffentlichung machen. Sie sind atomar/threadsicher, unabhängig davon, wie sie veröffentlicht werden. Die einzigen möglichen betreffen könnte die Veröffentlichung des Zustands der Instanzvariablen sein. Wir können nicht sagen, ob dies geschieht, ohne den Rest der Klasse zu betrachten. Zum Beispiel:

  • sind die Variablen final oder volatile?
  • Wenn sie nichtflüchtig und nicht endgültig sind, ist der Zugriff auf sie ordnungsgemäß synchronisiert?
  • sind sie Thread-begrenzt nach run() heißt?

beachte, dass die Runnables in dem aktuellen Thread instanziiert werden, nicht in den Gewindegängen, die erstellt werden, wenn (und falls) tA.start() und tB.start() genannt werden. Wenn start() aufgerufen wird, gibt es eine passiert-vor zwischen dem aktuellen Thread start() Anruf und dem neuen Thread run() Anruf. Dies bedeutet, dass eine sichere Veröffentlichung der Variablen für den untergeordneten Thread selbst gewährleistet ist. Es ist nur die Veröffentlichung der Variablen in anderen Threads, die von Bedeutung sind.

+0

"Ich kann nicht sofort sehen, wie das sein könnte" - wenn auf die Zähler außerhalb von neu erstellten Threads als Instanzvariablen der Runnables zugegriffen wird. Die im Konstruktor initialisierten Werte sind vor dem Zugriff nicht garantiert sichtbar, es sei denn, es wird mindestens eine der Instanzvariablen final deklariert, siehe https://shipilev.net/blog/2014/safe-public-construction/ –

+0

Nun ja ... aber wie kann auf diese Variablen mit * ally * zugegriffen werden, bevor der Konstruktor zurückkehrt? Sehen Sie sich den Code für den Konstruktor an. (Ich weiß, was sichere Veröffentlichung bedeutet, und "final" ist nur ein Weg, um es zu erreichen.) –

+0

"Wenn start() aufgerufen wird, gibt es ein passiert-vorher zwischen dem Aufruf des aktuellen Threads() und dem neuen Thread ausgeführt() call. Dies bedeutet, dass eine sichere Veröffentlichung der Variablen für den untergeordneten Thread selbst gewährleistet ist. " Dies ist ein Punkt, den ich nützlich finde. Zum Beispiel muss man die "Argumentvariablen" (this.counterA, this.counterB) nicht als endgültig in Runnable, even deklarieren - obwohl Runnable im Hauptthread erstellt wird und später auf diese Argumentvariablen im Thread, der erstellt wird. –

Verwandte Themen