# synchronized & volatile



## hdi (2. Mrz 2010)

Hey,

also ich hab schon vor ein paar Wochen etwas bzgl. volatile gefragt. Aber so komplett hab ich diese ganze Geschichte - auch in Verbindung mit synchronized - noch nicht begriffen. Ich sag euch mal was ich darüber denke und ihr sagt mir ob es richtig ist 

Also synchronized kann man bei Primitiven nicht benutzen. D.h. man sollte sich dafür ein Objekt nehmen auf das man synchronisiert - entweder die Primitive reinkapseln oder halt "extern" schauen dass alle Threads auf so ein Pseudo-Objekt synchen beim Zugriff auf das Primtive.

Bsp:


```
class Test{
 public static int count = 0;
 public static boolean running = true;
 public static Object lock = new Object();
}

class SomeThread extends Thread{
 public void run(){
     while(Test.running){
        synchronized(Test.lock){
            if(Test.count < 1000){
               Test.count++;
            }
         }
   
        if(getSomeRandomNumber() == 234){
            Test.running = false;
        }
      }
}
```
 
Test.count kann jetzt bei mehreren SomeThreads niemals 1001 werden wg. synch auf dem lock, right?
Aber was ist wenn Thread 1 Test.running auf false setzt - das bekommt Thread 2 glaub ich nich zwangsläufig mit oder? Dafür müsste man dann Test.running volatile machen, stimmt das?

Generell ist mir noch nicht ganz klar wie volatile und synchronized zusammenspielen. Wenn ich zB die if-Abfrage oben auch in den synch-Block des "lock" schiebe, führt das dazu dass diese Variablen (zB Test.running) von jedem Thread bei jedem Durchlauf neu geladen werden? Eigentlich haben sie ja mit dem "lock" nichts zu tun oder.

Also wann muss ich bei Primitiven volatile nehmen? _IMMER _wenn mehrere Threads darauf zugreifen? Und was bringt ein volatile bei Objekten? Wird durch Punkt-Notation nicht immer neu derefernziert, auch ohne volatile?

Okay also nochmal kurz und knapp, im Moment verstehe ich das ganze so. Im Bezug auf Multi-Thread wenn mehrere Threads eine Resource nutzen...
- ...und sie ein Objekt ist dann darauf synchen. Alle Werte die ausgelesen werden sind die aktuellsten weil durch Punkt-Notation die aktuellen Wert jedesmal neu ausgelesen werden
- ...und sie ein Primitive ist, dann kann ich nicht direkt synchen sondern mach mir ein Pseudo-Objekt dass ich als Lock nutze
- ...allerdings garantiert das nicht dass ein Thread beim Zugriff auf das Primtive tatsächlich den aktuellen Wert nimmt, dazu müsste ich es volatile machen

???:L

Danke!


----------



## ice-breaker (2. Mrz 2010)

JAX TV: Java-Programmierung im Multicore-Zeitalter
da wird einiges über synchronized und volatile erzählt, ist wirklich gut.


----------



## eRaaaa (2. Mrz 2010)

Oder den Artikel von ihr lesen:
AngelikaLanger.com - Regeln für die Verwendung von volatile - Angelika Langer Training/Consulting


----------



## hdi (3. Mrz 2010)

edit: Moment mal ich muss noch überlegen... Text kommt gleich


----------



## hdi (3. Mrz 2010)

So okay also ich hab mir jetzt mal ne Übersicht geschaffen und ich glaube ich hab das ganze jetzt schon mehr verstanden, aber es gibt noch immer Fragen. Ich texte mal drauf los und ihr hackt ein wenn ich Mist rede 

volatile hat erstmal gar nix mit synchen zu tun. Das bezieht sich nämlich nur auf die Sichtbarkeit, Stichwort Java Memory Model aus dem Video. Generell ist es so, dass wenn ich nicht synche, Änderungen auf einer Variablen in anderen Threads nicht zwangsläuftig sichtbar werden. Und zwar egal ob das jetzt Primitive sind oder Objekt-Variablen. Right?

Nun kann ich volatile verwenden, damit ich solche Sichtbarmachungen garantiere. Allerdings _eigentlich _nur auf Primitiven, da ich bei Objekt-Variablen die Referenz manipulieren müsste, sprich neue Zuweisung und das will/kann man ja wohl meistens nicht.
Zusammen mit einer atomaren Operation ist also ein volatile eine synchronisierte (da atomare) und sicherlich sichtbar gemachte Änderung. Nur dass es performanter ist als ein synchronized.

Synchronized brauch ich aber schon mal auf jeden Fall wenn ich ein "Operation Compound" habe, um Race Conditions zu vermeiden. Und synchronized enthält *immer *die Effekte eines volatile, richtig?

Jetzt frag ich mich aber inwiefern. Im Video gab es sinngemäß das Bsp:


```
private int count;
public synchronized void changeCount()  { ... }
public int size() { return count; }
```

Mehrere Threads verändern den count, und einer ruft die size() auf. Da diese nicht synched ist kann es sein dass da ein alter Wert gelesen wird. Das könnte ich beheben durch volatile beim count. Okay.
Oder - und das versteh ich nicht ganz - indem ich auch die size() synchronisiere. Warum?

Was genau passiert wenn ein synchronized Block betreten wird? Da werden dann alle Attribute des Objekts refreshed oder was? Und was ist wenn das nicht-Primitive sind? Sagen wir ich hab als Attribut ne komplexe Klasse die intern nochmal n Array von Arrays hat usw und da drin wurde jetzt von einem Thread etwas geändert. Und das ist dann refreshet wenn ich den Getter für dieses Attribut von nem anderen Thread aufrufe wenn ich synche? Ich meine wieweit geht das denn in die "Tiefe" damit? 

Also im Endeffekt ist das jetzt noch das große Fragezeichen über meinem Kopf: Was genau wird refresht wenn ich einen synchronized Block betrete?

Jetzt noch ein Bsp mit statics:

```
public class Test {

	public static int count;
	public static boolean running;
	
	public static void main(String[] args) {
		running = true;
		count = 0;
		new SomeThread().start();
		new SomeThread().start();
	}
}

public class SomeThread extends Thread {

	@Override
	public void run() {
		while (Test.running) {
			if (Test.count < 100000) {
				Test.count++;
			}
			System.out.println(Test.count);
		}
	}
}
```

Also erstmal ist das nicht synchronisiert, und solange die Variablen static bleiben sollen kann ich das nur synchen indem ich mir ein Pseudo-Objekt erstelle, denn ein volatile würde nix bringen da Test.count++ nicht atomar ist. D.h. ich muss sowas machen:


```
public void run() {
		while (Test.running) {
                        synchronized(Test.lockObject){
			     if (Test.count < 100000) {
			       	Test.count++;
			     }
			    System.out.println(Test.count);
                         }
 		}
	}
```

Aber das unterbindet lediglich das Switchen innerhalb der Logik der Threads, aber noch nicht dass zB wenn ein Thread Test.running auf false setzt, die anderen das mitkriegen. Oder überhaupt: Jeder liest noch immer evtl. seinen eigenen count aus, denn das lockObject hat ja eig. gar nix mit dem count zu tun, ist ja ne ganz andere Variable.

Also müsste ich _zusätzlich _ein volatile vor running und count klatschen.

Zusammenfassung: Bei *statischen Primitiven* brauch ich immer volatile, und sofern die Mainupulationen nicht atomar sind außerdem noch irgendein Objekt auf dem ich synchronisiere wenn ich diese Manipulationen mache.
Bei nicht-statischen Variablen kann ich mir ein volatile immer sparen solange ich auf das Objekt, in dem diese Variablen als Attribute definiert sind, synche - denn wenn man auf ein Objekt syncht werden alle Attribute - bis in die "hintersten Ecken" sozusagen - refresht.

Richtig oder falsch?


----------



## eRaaaa (3. Mrz 2010)

hdi hat gesagt.:


> Mehrere Threads verändern den count, und einer ruft die size() auf. Da diese nicht synched ist kann es sein dass da ein alter Wert gelesen wird. Das könnte ich beheben durch volatile beim count. Okay.
> Oder - und das versteh ich nicht ganz - indem ich auch die size() synchronisiere. Warum?
> 
> Was genau passiert wenn ein synchronized Block betreten wird? Da werden dann alle Attribute des Objekts refreshed oder was?



fast...

Synchronized Methods (The Java™ Tutorials > Essential Classes > Concurrency)
----------------
[...] when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
----------------


----------



## hdi (3. Mrz 2010)

Ja okay.. ich würd jetzt zwar noch immer für nix meine Hand ins Feuer legen aber ich glaub so einigermaßen hab ich das jetzt verstanden mit dem ganzen sync und volatile zeug 

Danke!


----------



## hdi (3. Mrz 2010)

Ach, noch eine klitzekleine Frage, wenn ich so ne typische Lifetime Variable hab:
*
edit: Hab grad gesehen genau das wird in dem Artikel gezeigt! JA man muss volatile machen *


```
class C extends Thread{

  private boolean alive;

  public void setAlive(boolean alive){
       this.alive=alive;
  }

  public void run(){
       alive = true;
       while(alive){...}
   }
}
```

und ich ruf von nem anderen Thread setAlive(false) auf, ist das dann für diesen hier sichtbar? D.h. muss ich auch meine eigenen Attribute volatile machen, bzw. erstellt der andere Thread dann irgendwie ne lokale Kopie davon in seinem Cache und setzt dann lediglich diese auf false?


----------



## FArt (3. Mrz 2010)

> JA man muss volatile machen


Nein, muss man nicht. volatile ist die günstigere Variane, aber das Setzen und Auswerten des Flags über den gleichen Monitor zu synchronisieren führt zu dem selben Ziel.

Am besten beschreibt den Zusammenhang tatsächlich die JSR-133 (die Stellen sind einigermaßen verständlich). Wenn man "Happens-Before-Relationship" verstanden hat (und wann dies garantiert wird), dann wird klar was volatile und synchronized gemeinsam haben... und was nicht.


----------



## hdi (4. Mrz 2010)

Ok nochmal zum Abschluss bitte, spielt es jetzt ne Rolle auf was ich eig. synche?

Bsp:


```
synchronized(something){
    a = 4;
    b++;
}
```

Die Änderungen von a und b sind hier also für einen anderen Thread der diesen Block betrifft immer sichtbar, obwohl das Objekt nicht direkt etwas damit zu tun hat, ja? Weil Thread 1 beim Verlassen des synch die Werte von a und b in den main memory flusht und Thread 2 beim Betreten die Zugriffe auf dem main memory macht?


----------



## FArt (4. Mrz 2010)

Vergiss die Sache mit dem Speicher usw.

Ja, wer auch immer den synchronisierten Block betritt ist allein da drin und sieht die Änderungen von Threads, die ihn davor betreten und wieder verlassen haben.


----------

