synchronized

OliW

Aktives Mitglied
Hallo Leute,

kann mir einer der werten Jave-Versteher .-) erklären, weshalb folgender Code nicht synchronisiert?
Hier soll durch 2 Threads die Variable x durch die Schleife auf den Wert 4.000 gezählt werden.
Die Werte sind allerdings bei jedem Durchgang immer noch unterschiedlich trotz Synchronisation.o_Oo_O

Java:
public class SynchedThreads2 implements Runnable {
    
    static Object lock= new Object(); 
        
        int x; 
        
        @Override
        public void run() { 
            int i; 
            for (i=0; i<2000; i++) { 
                synchronized(lock) { 
                    x++; 
                }
                
            }
            System.out.println(Thread.currentThread().getName() 
                    + " has finished after " + i + " loops");
            
        }

        public static void main(String[] args) {
            
            CreazyThreads2 c = new CreazyThreads2(); 
            new Thread(c).start();
            new Thread(c).start();
            
            try {
                Thread.sleep(500);
            }catch (InterruptedException e) { 
                e.printStackTrace();
            }
            synchronized(lock) {
            System.out.println("x is: " +c.x);
        }
    }

}
 

httpdigest

Top Contributor
Statt mit Thread.sleep() eine beliebige Zeit zu warten, kannst du auch einfach Thread.join() verwenden:
Java:
public class SynchedThreads2 implements Runnable {
  static Object lock = new Object();
  int x;
  @Override
  public void run() {
    int i;
    for (i = 0; i < 2000; i++) {
      synchronized (lock) {
        x++;
      }
    }
    System.out.println(Thread.currentThread().getName() + " has finished after " + i + " loops");
  }
  public static void main(String[] args) throws InterruptedException {
    SynchedThreads2 c = new SynchedThreads2();
    Thread t1 = new Thread(c);
    t1.start();
    Thread t2 = new Thread(c);
    t2.start();
    t1.join(); // <- Auf den ersten Thread warten
    t2.join(); // <- Auf den zweiten Thread warten
    synchronized (lock) {
      System.out.println("x is: " + c.x);
    }
  }
}
 

White_Fox

Top Contributor
Wenn ich das hier:
richtig verstehe, dann synchronisierst du den Zugriff auf dein Object lock. Du willst aber den Zugriff auf dein int synchronisieren.

Womit ich sehr gute Erfahrungen gemacht habe ist außerdem das hier:
 

OliW

Aktives Mitglied
Ah, der Titel für ein neues Spiel: Crazy Threads 2 :)

Ich würde aber dann schon auch SynchedThreads2 instantiieren und nicht CreazyThreads2:
Java:
        public static void main(String[] args) {

            SynchedThreads2 c = new SynchedThreads2();
...

oh man. Ich nehme alles zurück und behaupte das Gegenteil. Das kommt davon wenn man älteren Code kopiert und bei den Anpassungen etwas vergisst.

Mission Problem: gelöst :))))

thx alot .-)
 

looparda

Top Contributor
Damit hält er alle Threads an.
Hö? Durch synchronized Threads anhalten? Sobald man in der main aus dem synchronized-Block rausgeht kommen die Threads ja wieder an die Reihe (sofern sie nicht eh schon terminiert sind).

Die Threads sind ja längst terminiert zu dem Zeitpunkt, nach dem wait. Jedenfalls auf meiner Kiste.
Angenommen sie wären nicht terminiert, dann würde der Main-Thread durch den Monitor Zugriff bekommen, x ausgeben und die Threads würden im Hintergrund ihre Arbeit fertig machen. Also das gleiche wie ohne den synchronized-Block.
 

White_Fox

Top Contributor
Ich sollte den Code vielleicht wirklich mal genauer lesen und nicht nur überfliegen bevor ich in die Tastatur haue. :(
Ich schätze mal er wollte den Zugriff von seinem System.out-Aufruf auf sein x mit den Threads synchronisieren. In diesem Fall kann man wohl wirklich darauf verzichten.

Ja, wenn die Threads schnell genug durch sind und die Wartezeit ausreicht, sind sie wohl terminiert. Bis du nachgeschaut hast sind sie auf jeden Fall terminiert, denn die laufen ja auch weiter wenn du die main z.B. mit dem Debugger anhältst.
 

looparda

Top Contributor
Bei mir hängt das bekanntermaßen davon ab, wie schnell ich kurble :)
Da mir selbst bewusst war, dass es verschiedene Kisten gibt habe ich die beide Fälle durchdacht, die man durch anpassen der Wartezeit provozieren kann:
A) Threads bereits terminiert
B) Threads noch nicht terminiert
und komme zu dem Ergebnis, dass es ohne und mit synchronized Block das gleiche ergibt. Und somit kam die Frage auf, wofür der Block dann dort ist.
Meine Gedankengänge waren
A) ich habe synchonized nicht ganz durchdrungen
B) ich übersehe etwas
C) jemand hat den Block dort benutzt in der fälschlichen Annahme, dass dort auf die Terminierung der Threads gewartet wird.
C.1) das würde jedoch auch wieder in Widerspruch zum vorherigen Warten mit Thread.sleep stehen. Wäre dann ja doppelt gemoppelt...
D) höäähh?
 

mihe7

Top Contributor
und komme zu dem Ergebnis, dass es ohne und mit synchronized Block das gleiche ergibt.
Wenn wir davon ausgehen, dass die Threads noch laufen, gibt es schon einen Unterschied, denn x++ ist nicht atomar, die Zuweisung an ein int dagegen schon. Letztlich ist das aber graue Theorie, denn den Unterschied wird man nicht merken :)
 
X

Xyz1

Gast
Bei mir hängt das bekanntermaßen davon ab, wie schnell ich kurble :)
Die Sache ist einfach die, dass sleep() keine Zusicherung gibt, dass danach alle Threads schon "fertig" sind. (Das synchronized auch nicht.)

Durch das reservieren starten und wechseln der Threads ist es nicht ganz unrealistisch, dass 500ms nicht ausreichend seien können...
 

OliW

Aktives Mitglied
Die Sache ist einfach die, dass sleep() keine Zusicherung gibt, dass danach alle Threads schon "fertig" sind. (Das synchronized auch nicht.)

Durch das reservieren starten und wechseln der Threads ist es nicht ganz unrealistisch, dass 500ms nicht ausreichend seien können...

Die Überlegung war tatsächlich, wenn die Zeit nicht ausreicht, geht man mit dem zusätzlichen Synch-Block auf Nummer Sicher.
 
X

Xyz1

Gast
Also das nochmal aufrollen. Der Code war an für sich richtig, bis auf das nicht Joinen der Threads, das sleep() und das nicht zwingend notwendige synchronized. Das synchronized um das c.x würde sich nur einen Platz in der Warteschlange reservieren um den x Wert auszugeben, danach ginge es in der Warteschlange weiter. Je nachdem welchen Wert x dann hat, kann irgendwas ausgegeben werden.
Ansonsten eben noch Typo im Eifer des Gefechts... Schreibe SynchedThreads2 anstatt CreazyThreads2.
 
X

Xyz1

Gast
Außerdem ist noch gar nicht diskutiert worden, dass es idR keine Zusicherung gibt dass c.x NICHT gecached würde... Wenn es gecached würde, käme da ein Wert um 2000 herum heraus.
 

mihe7

Top Contributor
Die Variable dürfte schon gecached werden, allerdings spielt das, wenn ich es richtig sehe, hier keine Rolle, da in der Schleife synchronisiert wird und am Ende von t1, t2 ebenso.
 

looparda

Top Contributor
Nochmal zur Situation, dass die Threads noch arbeiten zum Zeitpunkt der Ausgabe:
Wenn wir davon ausgehen, dass die Threads noch laufen, gibt es schon einen Unterschied, denn x++ ist nicht atomar, die Zuweisung an ein int dagegen schon. Letztlich ist das aber graue Theorie, denn den Unterschied wird man nicht merken
Das Inkrementieren ist synchronisiert und das Schreiben erfolgt somit unterbrechungsfrei.
Allerdings kann es passieren, dass ich einen halbmodifizierten int lese, wenn ich
System.out.println("x is: " + c.x); ohne synchronized Block schreibe. Denn nur mit synchronized-Block um die Ausgabe ist sichergestellt, dass ich erst lese, wenn das Schreiben abgeschlossen wurde.
Hab ich das richtig verstanden?
 
X

Xyz1

Gast
Mein Gott, sollen wir das auch noch aufmalen? :D

c.x++ ist durch das synchronized Thread-safe.
Wenn sichergestellt ist, dass beide Threads vor der Ausgabe fertig sind, so braucht System.out.println("x is: " + c.x) nicht auch noch Thread-safe sein.
Thread-Safety verhindert lediglich gleichzeitigen Zugriff auf eine Ressource, wobei das "Gleichzeitig" bei der Ausgabe nicht gegeben ist.
 
X

Xyz1

Gast
Ich würde es begrüßen, wenn du in Zukunft nicht auf Fragen von mir eingehst. Vielen Dank.
Wer ist jetzt angesprochen? Ich kann nichts dafür, wenn Du Antworten nicht verstehst. Zudem kannst Du Dir nicht aussuchen, wer Dir antworten soll, wenn Du zuvor ALLE ansprichst.

Aber dennoch viel Erfolg beim Entwickeln von Verständnis...
 

looparda

Top Contributor
Wer ist jetzt angesprochen? Ich kann nichts dafür, wenn Du Antworten nicht verstehst. Zudem kannst Du Dir nicht aussuchen, wer Dir antworten soll, wenn Du zuvor ALLE ansprichst.
Natürlich warst du angesprochen. Mit deiner Antwort, die sich nicht auf den gegebenen Fall (Nochmal zur Situation, dass die Threads noch arbeiten zum Zeitpunkt der Ausgabe) bezieht.
Ich habe gesagt in Zukunft. Zukunft bedeutet in dem Fall ab dem Beitrag, in dem ich Zukunft benutzt habe und nicht in denen davor, auf die du dich beziehst (auch erkennbar am Wort "zuvor").
Ich kann nichts dafür, wenn Du Antworten nicht verstehst.
Ich denke du hast meine Frage zu oberflächlich verstanden. Mir geht es darum, ob durch das synchronized sichergestellt ist, dass für den lesenden Thread das Schreiben sichtbar ist und er nicht einen alten Wert ausgibt, weil ich im Thema Happens-Before-Beziehung, volatile und Sichtbarkeit noch nicht sicher bin.
Wenn für dich das Thema mit "ich baue eine Wartezeit ein oder stelle sicher, dass die Threads zum Zeitpunkt der Ausgabe terminiert sind" abgeschlossen ist, dann ist das doch ok, aber reduziere meine weitergehenden Fragen nicht darauf.
 

mihe7

Top Contributor
synchronized sorgt beim Eintritt in den Block dafür, dass die Werte frisch in den Cache geladen werden. Danach darf der Compiler davon ausgehen, dass die Werte nicht von außen verändert werden.
Mir geht es darum, ob durch das synchronized sichergestellt ist, dass für den lesenden Thread das Schreiben sichtbar ist und er nicht einen alten Wert ausgibt, weil ich im Thema Happens-Before-Beziehung, volatile und Sichtbarkeit noch nicht sicher bin.
Nein, alleine durch einen synchronized-Block im schreibenden Thread ist nicht sichergestellt, dass ein lesender Thread aktuelle Werte erhält. Wenn die Variable volatile ist, dann schon. Mal sehen, ob ich da ein Beispiel hinbekomme.
 

mihe7

Top Contributor
Das ging ja leichter als gedacht:
Java:
public class Test {
    private int x;

    public void start() {
        Thread t1 = new Thread(() -> {
            while (x < 1000) {
                synchronized(Test.this) {x++;}
            }
            System.out.println("T1 done");
        });
        Thread t2 = new Thread(() -> {
            while (x < 1000) ;
            System.out.println("T2 done");
        });

        t2.start();
        t1.start();
    }

    public static void main(String[] args) {
        new Test().start();
    }
}
Ggf. ein paar mal ausführen.

Nachtrag: wird x volatile deklariert, ist das Problem natürlich behoben.
 
X

Xyz1

Gast
Nein, alleine durch einen synchronized-Block im schreibenden Thread ist nicht sichergestellt, dass ein lesender Thread aktuelle Werte erhält. Wenn die Variable volatile ist, dann schon. Mal sehen, ob ich da ein Beispiel hinbekomme.
Doch, wenn 2. synchronized ist, dann schon.

@looparda Wäre, in diesem Fall, gar nichts synchronized und die Ausgabe erfolgte unmittelbar, so würde irgendein Wert zwischen 0 und 4000 oder aber random ausgegeben werden, wenn eine schreib Operation noch nicht vollständig wäre... Das passiert aber nur äußerst selten.
 

looparda

Top Contributor
Nachtrag: wird x volatile deklariert, ist das Problem natürlich behoben.
Was sind die erwarteten Ausgaben/Verhalten? Ich denke das Problem soll in while (x < 1000) ; in t2 stecken.
Bei mir Verhalten sich beide Varianten mit und ohne volatile von den Ausgaben gleich. Mal erhalte ich
T1 done
T2 done und mal in umgekehrter Reihenfolge. Deswegen bin ich verwirrt auf was ich achten soll.
@looparda Wäre, in diesem Fall, gar nichts synchronized und die Ausgabe erfolgte unmittelbar, so würde irgendein Wert zwischen 0 und 4000 oder aber random ausgegeben werden, wenn eine schreib Operation noch nicht vollständig wäre... Das passiert aber nur äußerst selten.
Es geht mir immernoch um die beiden Varianten, dass ich in der main die Ausgabe in einen synchronized-Block packe oder eben nicht und dessen Auswirkungen und nicht darum, ob ich beim Schreiben synchonized benutze. Bei zwei Threads, die konkurrierend auf eine Ressource schreiben wollen steht synchronized dort doch gar nicht zur Debatte.
Also A
Java:
public static void main(String[] args) {

    SynchedThreads2 c = new SynchedThreads2();
    new Thread(c).start();
    new Thread(c).start();
    synchronized(lock) {
        System.out.println("x is: " +c.x);
    }
}
vs. B
Java:
public static void main(String[] args) {

    SynchedThreads2 c = new SynchedThreads2();
    new Thread(c).start();
    new Thread(c).start();
    System.out.println("x is: " +c.x);
}
Meine Gedanken zu den Problemen von B waren:
Das Inkrementieren ist synchronisiert und das Schreiben erfolgt somit unterbrechungsfrei.
Allerdings kann es passieren, dass ich einen halbmodifizierten int lese, wenn ich
System.out.println("x is: " + c.x); ohne synchronized Block schreibe. Denn nur mit synchronized-Block um die Ausgabe ist sichergestellt, dass ich erst lese, wenn das Schreiben abgeschlossen wurde [Happens-Before-Beziehung, Sichtbarkeit, volatile].
Hab ich das richtig verstanden?
Hier hatte ich folgende Probleme im Hinterkopf:
Mir geht es darum, ob durch das synchronized sichergestellt ist, dass für den lesenden Thread das Schreiben sichtbar ist und er nicht einen alten Wert ausgibt, weil ich im Thema Happens-Before-Beziehung, volatile und Sichtbarkeit noch nicht sicher bin.
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Deswegen bin ich verwirrt auf was ich achten soll.
Sorry, es kann passieren, dass T2 nicht beendet wird, weil der Thread die aktuellen Werte von x nicht sieht. Allerdings könnte in dem Code passsieren, dass der Compiler die Schleife wegoptimiert. Besser so:
Java:
public class Test {
    private int x;

    public void start() {
        Thread t1 = new Thread(() -> {
            while (x < 1000) {
                synchronized(Test.this) {x++;}
            }
            System.out.println("T1 done");
        });
        Thread t2 = new Thread(() -> {
            while (getX() < 1000) ;
            System.out.println("T2 done");
        });

        t2.start();
        t1.start();
    }

    private int getX() { return x; }

    public static void main(String[] args) {
        new Test().start();
    }
}
 

looparda

Top Contributor
Sorry, es kann passieren, dass T2 nicht beendet wird, weil der Thread die aktuellen Werte von x nicht sieht. Allerdings könnte in dem Code passsieren, dass der Compiler die Schleife wegoptimiert. Besser so:
Ich verstehe das Problem, aber kann das Verhalten leider nicht provozieren.
Ein gutes Beispiel, bei dem man den Unterschied provozieren kann ist dieses:
Java:
class TestVolatile extends Thread {

    //volatile
    boolean keepRunning = true;

    public void run() {
        long count=0;
        while (keepRunning) {
            count++;
        }

        System.out.println("Thread terminated." + count);
    }

    public static void main(String[] args) throws InterruptedException {
        TestVolatile t = new TestVolatile();
        t.start();
        Thread.sleep(1000);
        System.out.println("after sleeping in main");
        t.keepRunning = false;
        t.join();
        System.out.println("keepRunning set to " + t.keepRunning);
    }
}
Ich habe versucht einen Unterschied zwischen den Beispielen A und B nachzuweisen, aber es gelingt mir nicht. Es ist auch einfach schwer nachzuweisen, dass man einen gecachten Wert erhalten hat, statt den tatsächlichen.
Weiterhin habe ich etwas recherchiert:
http://gee.cs.oswego.edu/dl/cpj/jmm.html hat gesagt.:
When synchronization is used consistently, each of these properties has a simple characterization: All changes made in one synchronized method or block are atomic and visible with respect to other synchronized methods and blocks employing the same lock.
Also sollte es doch einen Unterschied geben.
 

httpdigest

Top Contributor
Die Anzahl der Iterationen muss mindestens so groß sein wie der C2 CompileThreshold der JVM. Ändere z.B. mal die Iterationsanzahl im Code von @mihe7 auf 10000000. In einigen Fällen beendet er sich dann nicht mehr bei mir.
Bei deiner while-Schleife wird die Anzahl der Iterationen, in denen der C2 optimiert, sehr schnell erreicht werden und dann sollte er die boolean Variable auch nur noch einmal lesen.
 

looparda

Top Contributor
Die Anzahl der Iterationen muss mindestens so groß sein wie der C2 CompileThreshold der JVM. Ändere z.B. mal die Iterationsanzahl im Code von @mihe7 auf 10000000. In einigen Fällen beendet er sich dann nicht mehr bei mir.
Ja, damit kann ich es provozieren.
Das witzige ist: wenn ich nach ein paar Sekunden einen Breakpoint an while (getX() < 10000000) setze, der Debugger dort anhält und ich das Programm weiterlaufen lasse, dann terminiert t2 immer. Programmflusssteuerung durch den Debugger, cool!
 

looparda

Top Contributor
Mit Debugger und ohne Breakpoint verhält es sich aber wie beim Run. Nur wenn ich einen Breakpoint wie beschrieben setze passiert es.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
frager2345 Thread - Methoden synchronized deklarieren Java Basics - Anfänger-Themen 10
berserkerdq2 Wo finde ich in der Java Api die Notation zu Threads bezüglich Synchronized? Java Basics - Anfänger-Themen 14
A Thread - Synchronized Java Basics - Anfänger-Themen 10
berserkerdq2 Findet eine parallele Verarbeitung in Java bei Threads erst statt, wenn man die Methoden auch synchronized? Und wie sieht bei Conditions aus? Java Basics - Anfänger-Themen 8
X Threads Zwei Threads, aber doppelte Ausgabe verhindern (synchronized) Java Basics - Anfänger-Themen 54
O synchronized difference Java Basics - Anfänger-Themen 5
E Synchronisierte Methoden vs. Synchronized(lockObject) Block Java Basics - Anfänger-Themen 7
T Was bringt das synchronized bei der Methode? Java Basics - Anfänger-Themen 12
temi Synchronized(Monitor) Java Basics - Anfänger-Themen 2
Z Threads Threads - Zugriff auf Ressourcen ohne(Lock, Synchronized) Java Basics - Anfänger-Themen 2
Shams Synchronized-Schlüsselwort bei Inkrementierung einer statischen Variable Java Basics - Anfänger-Themen 13
V Parameter in synchronized-Blöcken verstehen Java Basics - Anfänger-Themen 2
M Threads synchronized und wait Java Basics - Anfänger-Themen 2
N Threads Probleme mit synchronized Java Basics - Anfänger-Themen 9
B synchronized threads Java Basics - Anfänger-Themen 17
J Threads Synchronized Java Basics - Anfänger-Themen 6
U synchronized / lock Java Basics - Anfänger-Themen 8
P Arraylist synchronized? Java Basics - Anfänger-Themen 6
X3TitanCore Methoden synchronized bei einer Methode Java Basics - Anfänger-Themen 2
P synchronized methoden Java Basics - Anfänger-Themen 3
B warum schließt synchronized andere threads nicht aus? Java Basics - Anfänger-Themen 7
M Synchronized klappt nicht Java Basics - Anfänger-Themen 11
E synchronized Methoden Java Basics - Anfänger-Themen 3
M synchronized( ref ) Java Basics - Anfänger-Themen 3
I Synchronized Threads Java Basics - Anfänger-Themen 4
R Problem: Threads Synchronized machen Java Basics - Anfänger-Themen 5
M OOP Synchronized Methoden, zugriff aus Threads Java Basics - Anfänger-Themen 4
X Threads und synchronized - Verständnisproblem Java Basics - Anfänger-Themen 3
M Kleines Problem mit Threads (synchronized) Java Basics - Anfänger-Themen 3
S Fragen zu synchronized + Singleton! Java Basics - Anfänger-Themen 10
S bin zu blöd für threads - wait, notify, synchronized Java Basics - Anfänger-Themen 11
J simple Frage zu synchronized Java Basics - Anfänger-Themen 4
S Threads: synchronized mach nicht was es soll? Java Basics - Anfänger-Themen 6
L Threads und synchronized Java Basics - Anfänger-Themen 8
R wait() in synchronized - Block oder nicht? Java Basics - Anfänger-Themen 4
X Synchronized Zugriff ArrayList<E> Java Basics - Anfänger-Themen 6
G synchronized Java Basics - Anfänger-Themen 5
M synchronized variables? Java Basics - Anfänger-Themen 8
B Verständnissfrage synchronized Java Basics - Anfänger-Themen 2
S Warum wirkt hier synchronized nicht? Java Basics - Anfänger-Themen 9
C Trotz "synchronized" unerwartete Ausgabe Java Basics - Anfänger-Themen 2
E Synchronized - Methoden in verschied. Klassen Java Basics - Anfänger-Themen 3
C synchronized Java Basics - Anfänger-Themen 2
J Fragen zu Synchronized Java Basics - Anfänger-Themen 6
T synchronized HashMap Java Basics - Anfänger-Themen 7
L Problem mit synchronized und String Java Basics - Anfänger-Themen 2
A Problem mit Threads und synchronized Java Basics - Anfänger-Themen 3
B Was bedeutet synchronized? Java Basics - Anfänger-Themen 8

Ähnliche Java Themen

Neue Themen


Oben