2015-02-16 6 views
5

Dieser Code ist von Effective Java (Artikel 66): (ohne Synchronisierung oder flüchtige diese endet nie)Warum verhält sich der Thread bei verschiedenen Methoden der run-Methode anders?

public class ThreadPractice { 
static boolean canrunstatic; 

public static void main(String[] args) throws InterruptedException { 

    Thread backgroundThread = new Thread(new Runnable() { 
     public void run() { 
      int i = 0; 
      while (!canrunstatic){i++;} 
      System.out.println("finished"); 
     } 
    }); 
    backgroundThread.start(); 
    TimeUnit.SECONDS.sleep(1); 
    canrunstatic = true; 
} 

Als Bloch in diesem Kapitel erwähnt wird es nie schreiben Sie an die Konsole „fertig“. Ich habe mit dieser Klasse spielen um, und diese Linie der runnable run-Methode hinzu:

System.out.println("im still running"); 

dies mit der while-Schleife erhöht nicht nur ich, sondern in jeder Schleife diese Zeichenfolge ausdruckt. Aber was macht mich verrückt, dass auf diese Weise der Faden nach 1 sec aufhört, wenn der Hauptfaden aus dem Schlaf kommt.

geändert: (hält ohne volatile/sync)

public class ThreadPractice { 
static boolean canrunstatic; 


public static void main(String[] args) throws InterruptedException { 

    Thread backgroundThread = new Thread(new Runnable() { 
     public void run() { 
      int i = 0; 
      while (!canrunstatic){i++;System.out.println("im still running");} 
      System.out.println("finished"); 
     } 
    }); 
    backgroundThread.start(); 
    TimeUnit.SECONDS.sleep(1); 
    canrunstatic = true; 


} 

Also, was die Logik dahinter ist?

Antwort

4

Gerade versprochen wird, ist es nur garantiert nicht, dass der Thread wird jemals aufhören, aber es ist nicht verboten dass es aufhört. Die Logik dahinter ist die Java Memory Model, die ein ziemlich kompliziertes Thema ist, aber benötigt wird, um Multithreading in Java zu verstehen.

Das Konzept ist, dass ein Schreiben in ein nichtflüchtiges Feld eines Threads nur dann von einem anderen Thread gesehen werden muss, wenn diese beiden Aktionen miteinander synchronisieren. Ein Compiler erlaubt es, einige Aktionen neu zu ordnen, wenn sich das Verhalten des Threads, in dem es ausgeführt wird, nicht ändert. Aber ein anderer Thread könnte das sehen. Sie benötigen also die richtige Synchronisation, um dem Compiler mitzuteilen, dass Neuordnung in einigen Teilen nicht zulässig ist.

Lesen Sie das vollständige Papier dazu hier: JSR-133

2

Beim Schreiben von Daten in die Konsole wird oft eine Thread-sichere Operation implementiert.

In diesem Fall kann das Schreiben von Daten in die Konsole auch die Aktualisierung der canrunstatic Variablen auslösen, wie von Ihrer backgroundThread erkannt.

Beachten Sie, dass dies nicht von dem Java-Speichermodell, noch durch die Implementierung von Java System.out

+2

Das ist nicht überall in dem Speichermodell spezifiziert ist. Das Schreiben in die Konsole ist eine externe Operation im JMM, aber dies garantiert nicht die Synchronisation, und es wird keine Kante mit Synchronisieren mit erstellt. Das ist also keine Erklärung für die Logik dahinter. – MinecraftShamrock

+0

Guter Punkt, das ist die Ursache, aber es ist nicht erforderlich, dass es passiert. Ich habe die Antwort aktualisiert, um dies zu reflektieren. – Thirler

Verwandte Themen