Zwei Threads, gleiche statische Variable, gleicher Wert, gleichzeitiger Zugriff

8


Ich habe versucht, mich für die SCJP Prüfung vorzubereiten, die ich nächste Woche machen muss, und ich bin auf diese Frage zu Java-Threads gestoßen.

%Vor%
  • Was ist wahr? (Wählen Sie alle zutreffenden Antworten aus.)
  • Die Ausgabe könnte P Q R S
  • sein
  • Die Ausgabe könnte P R S Q
  • sein
  • Die Ausgabe könnte P R Q S
  • sein
  • Die Ausgabe könnte P Q P Q
  • sein
  • Das Programm könnte einen Deadlock verursachen.
  • Kompilierung schlägt fehl.

Der Antwortschlüssel sagt:
A, B und C sind korrekt. Da pick () statisch ist und release () nicht statisch ist, gibt es dort sind zwei Schlösser. Wenn pick () nicht statisch wäre, wäre nur A korrekt.

Es sagt auch, dass die Ausgabe P Q P Q nicht wirklich eine Option ist und es nicht möglich ist, solche Ergebnisse zu erhalten.

Am Anfang glaubte ich nicht wirklich den Antwortschlüssel, aber dann sah ich, dass es wirklich nicht möglich ist, diese Ausgabe als Ergebnis dieser Anwendung zu sehen. (Nach dem Ausführen der Klasse.)

Nun, das ist der Teil, der mich ein wenig verwirrt, Und hier ist warum

Ich dachte, dass ein P Q P Q- oder ein R S R S -Ergebnis möglich gewesen sein muss. Weil es immer eine Chance für eine Situation gibt, die die Variablen-ID für beide Threads exakt gleich macht. Mit anderen Worten, zum Beispiel wenn der erste Thread gerade die Zeile 6 beendet hat, könnte er seine Runde an die andere übergeben, und danach könnte der andere den Wert der Variablen-ID ändern und dann voila! Sie könnten in den gleichen Block gehen, wenn sie glücklich sind. .

Ich habe versucht, diese Situation immer wieder zu sehen (mit Eclipse Juno und Java 7). Es passiert einfach nicht. Ich bin sicher, dass etwas mit meiner Art zu denken nicht stimmt, und ich frage mich, was es ist. Ich muss wissen, welche Regel diese beiden Threads daran hindert, auf die Variablen-ID in ihrem gleichen Zustand zuzugreifen.

    
3yanlis1bos 11.07.2013, 06:56
quelle

5 Antworten

6

Tatsächlich gibt es einige Möglichkeiten, einige extrem unwahrscheinlich, aber sie sind trotzdem möglich und nach 1 Million Hinrichtungen ist das, was ich gefunden habe.

Code:

%Vor%

Ergebnisse:

%Vor%

Ich denke, wir haben bewiesen, dass P Q P Q tatsächlich möglich ist, obwohl mit einer extrem niedrigen Wahrscheinlichkeit von eins in einer Million ...

[edit: ein anderer Lauf, andere Ergebnisse mit R S R S sind ebenfalls möglich:]

%Vor%     
vikingsteve 11.07.2013, 07:24
quelle
1

Ja, Sie haben recht, P Q P Q ist möglich.

Sie können die Wahrscheinlichkeit dieses Ereignisses durch die folgende Änderung erhöhen (die Semantik des Programms wird nicht beeinflusst):

%Vor%

Nach dem Anwenden dieser Änderungen habe ich P Q P Q nach ein paar Dutzend Läufen erhalten.

    
axtavt 11.07.2013 07:25
quelle
1

Ja, Ihr Verdacht ist richtig. Der Code in der run () -Methode ist jedoch einfach genug, um in einem CPU-Burst ausgeführt zu werden, sofern nicht auf andere Weise gewartet wird.

    
blackSmith 11.07.2013 07:29
quelle
1

Sie haben Ihre Annahme richtig. PQPQ ist in der Tat möglich, weil JLS-Spezifikation 17.4.3 gibt Folgendes an:

  

Unter allen Thread-Aktionen, die von jedem Thread t ausgeführt werden, ist die Programmreihenfolge von t eine Gesamtordnung, die die Reihenfolge widerspiegelt, in der diese Aktionen gemäß der Intra-Thread-Semantik von t ausgeführt würden.

     

Ein Satz von Aktionen ist sequenziell konsistent, wenn alle Aktionen in einer Gesamtreihenfolge (der Ausführungsreihenfolge) auftreten, die mit der Programmreihenfolge konsistent ist, und weiterhin sieht jeder Lesevorgang r einer Variablen v den vom Schreibvorgang w geschriebenen Wert in v so dass:

     
  • w kommt vor r in der Ausführungsreihenfolge und
  •   
  • es gibt keinen anderen Schreibvorgang, so dass w vor w kommt und w 'vor r in der Ausführungsreihenfolge steht.
  •   

Sequenzielle Konsistenz ist eine sehr starke Garantie, die bei der Ausführung eines Programms auf Sichtbarkeit und Reihenfolge gelegt wird. Innerhalb einer sequenziell konsistenten Ausführung gibt es eine Gesamtordnung über alle individuellen Aktionen (wie Lesen und Schreiben), die mit der Reihenfolge des Programms konsistent ist, und jede einzelne Aktion ist atomar und für jeden Thread sofort sichtbar.

AtomicInteger wären bessere Kandidaten um diese Situation zu vermeiden.

    
Dhrubajyoti Gogoi 11.07.2013 07:48
quelle
0
  

Wenn der erste Thread gerade die Zeile 6 beendet hat, könnte er seine Runde an die andere übergeben, und danach könnte die andere den Wert der Variablen-ID ändern und dann voila! Sie könnten gleich zum Block gehen, wenn sie glücklich sind.

Sagen wir, Thread 1 beginnt zuerst. Es dreht den Wert von id auf 0. Thread 1 ist jetzt in Zeile 8 gesperrt.

Thread 2 beginnt. Es sieht entweder den Wert von ID

  • 1

    Alle Threads dürfen Felder lokal zwischenspeichern, sofern sie nicht als flüchtig markiert sind. Thread 2 speichert den Wert von id.

    Thread 2 beginnt. Er dreht den Wert auf 0. Und beide geben den ersten if-Block ein. Hätte Thread 1 in Zeile 7 gesperrt. Die Ergebnisse könnten anders sein.

    Es ist möglich, dass der Ausgang P Q P Q

    ist
  • 0

    Es sieht den umgedrehten Wert von Thread 1

    Ändert den Wert erneut zu 1. Ruft den Else-Block auf.

    Der Fall der Optionen A, B, C

Es ist nicht einmal garantiert, dass Thread 1 vor Thread 2 beginnt.

    
bsd 11.07.2013 07:17
quelle