Wie funktioniert das Huckepackback der aktuellen Thread-Variable in ReentrantLock.Sync?

8

Ich habe einige Details zur Implementierung von ReentrantLock in "Java Concurrency in Practice" in Abschnitt 14.6.1 gelesen und etwas in der Anmerkung verwirrt mich:

  

Da die Methoden zur Manipulation des geschützten Zustands die Speichersemantik eines flüchtigen Lese- oder Schreibvorgangs haben, ist ReentrantLock darauf bedacht, das Besitzerfeld erst nach dem Aufruf von getState und nur vor dem Aufruf von setState zu lesen kann ReentrantLock die Speichersemantik des Synchronisationszustands übernehmen und somit weitere Synchronisation vermeiden, siehe Abschnitt 16.1.4.

der Code, auf den es sich bezieht:

%Vor%

Und ich glaube, das ist der vereinfachte Code von nonfirTryAcquire in ReentrantLock.Sync .

%Vor%

Der verwirrende Teil ist also, wie die Einstellung von owner , die lediglich eine einfache Instanzvariable in AbstractOwnableSynchronizer ist, für else if (current == owner) in anderen Threads sichtbar wird. Tatsächlich ist das Lesen von owner nach dem Aufruf von getState() (und state ist eine volatile qualifizierte Variable von AQS ), aber nach der Einstellung von owner gibt es nichts (kann eine Synchronisation erzwingen) Semantik) überhaupt. Data Race passiert?

Nun, angesichts der Autorität dieses Buches und des gründlich getesteten Codes kommen mir zwei Möglichkeiten in den Sinn:

  1. Die vollständige Barriere (sei es mfence oder 'lock'ed instruction) vor der Einstellung owner = current macht die versteckte Arbeit. Aber nachdem ich von mehreren berühmten Artikeln gelernt habe, kümmert sich die volle Schranke mehr um die davor geschriebenen wie auch die darauf folgenden Lesevorgänge. Nun, wenn diese Möglichkeit wahr ist, dann könnten einige Sätze in "JCIP" unangemessen angegeben werden.

  2. Ich stelle fest, dass ' setState(c+1) ' geographisch nach owner = current im Code-Snippet kommt, obwohl es sich in einem anderen Zweig von if-else befindet. Wenn das, was die Kommentare sagen, die Wahrheit ist, bedeutet das, dass die von setSate(c+1) eingefügte Barriere Synchronisationssemantik auf owner = current in einem anderen Zweig auferlegen kann?

Ich bin ein Neuling in diesem Bereich, und einige großartige Blogs helfen mir sehr dabei, zu verstehen, was der JVM zugrunde liegt (keine Bestellung):

sowie die immer großartig: Ссылка

Nachdem ich meine Hausaufgaben gemacht und im Internet gesucht habe, komme ich nicht zu einem befriedigenden Ergebnis.

Entschuldigen Sie, wenn das zu wortreich oder unklar ist (Englisch ist nicht meine Muttersprache). Bitte helfen Sie mir dabei, alles, was damit zu tun hat, wird geschätzt.

    
DarKeViLzAc 11.09.2013, 03:17
quelle

2 Antworten

2

Sie vermuten, dass zwischen owner = current; (nach dem CAS) und if (current == owner) (nach dem Lesen des Zustands und Überprüfen, ob es & gt; 0 ist) ein Wettlauf stattfinden könnte.

Wenn Sie dieses Stück Code isoliert betrachten, denke ich, dass Ihre Argumentation richtig ist. Sie müssen jedoch auch tryRelease berücksichtigen:

%Vor%

Hier wird der Besitzer auf null gesetzt, bevor der Status auf 0 gesetzt wird. Um die Sperre zu erhalten, muss der Status 0 sein und der Besitzer ist also null .

Folglich

  • Wenn ein Thread if (current == owner) mit c=1 erreicht,
    • es kann der besitzende Thread sein, in diesem Fall ist der Eigentümer korrekt und der Status wird inkrementiert.
    • es kann ein anderer Thread sein, der den neuen Besitzer sehen kann oder nicht.
      • Wenn es es sieht, ist alles in Ordnung.
      • Wenn nicht, wird null angezeigt, was ebenfalls gut ist.
  • Wenn ein Thread if (current == owner) mit c>1 erreicht,
    • es kann der besitzende Thread sein, in diesem Fall ist der Eigentümer korrekt und der Status wird inkrementiert.
    • es kann ein anderer Thread sein, aber der Besitzer wird sicher sein.

Ich stimme zu, dass die Fußnote "lese das Besitzerfeld nur nach dem Aufruf von getState und schreibe es nur vor dem Aufruf von setState " in JCIP ist irreführend. Es schreibt den owner vor dem Aufruf von setState in tryRelease , aber nicht tryAcquire .

    
ewernli 12.09.2013, 07:25
quelle
0

Dies wird in diesem Blogpost ziemlich gut erklärt. Die untere Zeile besagt, dass, wenn der Lese-Thread ein flüchtiges Feld liest, alle vom Schreib-Thread aktualisierten Felder, die vor dem Schreiben in das flüchtige Feld geändert wurden, auch für den Lese-Thread sichtbar sind. Die Sperrklasse organisiert die Feldzugriffe, um sicherzustellen, dass nur das Statusfeld flüchtig sein muss, und das Besitzerfeld wird bei Bedarf weiterhin sicher propagiert.

    
rolfl 11.09.2013 05:07
quelle