# Mehrere Threadszustände synchronisieren



## tuttle64 (14. Okt 2012)

Hallo allerseits
Ich habe ein solcher Thread, der verschiedene Zustände durchläuft, bis FINISH gesetzt wird. 


```
public class SynchronThread extends Thread {

	enum State {
		START, STEP1, STEP2, END, FINISH
	}

	public SynchronThread() {
		state = State.START;
	}

	private State state;

	public void run() {

		while (this.state != State.FINISH) {
			switch (state) {
			case START:
				System.out.println("Entering START state");
				System.out.println("Finish START state" );
				state = State.STEP1;
				break;
			case STEP1:
				System.out.println("Entering STEP1 state");
				System.out.println("Finish STEP1 state" );
				state = State.STEP2;
				break;
			case STEP2:
				System.out.println("Entering STEP2 state");
				System.out.println("Finish STEP2 state" );
				state = State.FINISH;
				break;
			default:
				break;
			}
		}
	}
```

Nun habe ich mehrere solcher Threads und die sollen alle erst enden, wenn alle STEP2 durchlaufen haben. Ist der Ansatz mit Switch-Case schon unglücklich oder kriege ich das noch hin? Falls ja, wie?


----------



## Bernd Hohmann (14. Okt 2012)

So wie es da steht, macht der Switch/Case keinen Sinn weil am Ende jedes Blocks der nächste State aufgerufen wird - da kannst Du es auch direkt hintereinander schreiben. Was ich auch so recht nicht verstehe: warum dürfen die Threads erst enden, wenn STEP2 durchlaufen wurde? Da hinter diesem Schritt nichts mehr kommt, sehe ich da im Moment keinen Grund dafür.

Was anderes wäre es, wenn sich der Thread schlafen legen soll bis sich der Status ändert. Dazu schau dir mal Object#wait() und Object#notify() an.

bernd


----------



## tuttle64 (14. Okt 2012)

Bernd Hohmann hat gesagt.:


> So wie es da steht, macht der Switch/Case keinen Sinn weil am Ende jedes Blocks der nächste State aufgerufen wird - da kannst Du es auch direkt hintereinander schreiben. Was ich auch so recht nicht verstehe: warum dürfen die Threads erst enden, wenn STEP2 durchlaufen wurde? Da hinter diesem Schritt nichts mehr kommt, sehe ich da im Moment keinen Grund dafür.
> 
> Was anderes wäre es, wenn sich der Thread schlafen legen soll bis sich der Status ändert. Dazu schau dir mal Object#wait() und Object#notify() an.
> 
> bernd




Hinter STEP2 kommen noch weitere case Zustände und wait()/notify() darf man in dieser Aufgabe nicht verwenden und die Abläufe in den STEPS müssen in separaten Threads laufen.


----------



## Bernd Hohmann (14. Okt 2012)

Man kann sich um notify/wait herumdrücken wenn man sich der Tools aus java.util.concurrency.* bedient, hier hab ich was zum Thema gefunden: java - What's the best alternative to wait...notify for low level synchronization? - Stack Overflow

Aber vielleicht könntest Du die Aufgabe kurz zitieren, das würde helfen.

Bernd


----------



## tuttle64 (14. Okt 2012)

Bernd Hohmann hat gesagt.:


> Aber vielleicht könntest Du die Aufgabe kurz zitieren, das würde helfen.



Stelle Dir vor, eine bestimmte Anzahl Köche (Threads) müssen eine bestimmte, gleiche Anzahl Menus zubereiten. Die Zubereitung kann erst beginnen, wenn alle Köche die Küche betreten haben. Sobald alle Köche Ihr Münu serviert haben, kann mit dem nächsten Durchgang gestartet werden. Der erste Durchgang ist dann beendet und der zweite Durchgang beginnt. 

Das Problem liegt darin, eine bestimmte Aufgabe erst dann zu starten, wenn die vorhergehende beendet worden ist. Man könnte jede Aufgabe als Thread implementieren und dann mit Join() wieder zusammenführen. Bei vielen Köchen und Aufgaben scheint mir das wenig praktikabel zu sein. 

Ich habe pro Koch einen Thread und darin alle Aufgaben gekapselt, die dann den Ablauf mit Switch-Case gesteuert. Allerdings fällt mir jetzt die synchronisierung schwer.


----------



## Bernd Hohmann (14. Okt 2012)

Vielleicht hilft (wie in einer Großlüche auch) ein "Maître de Cuisine".

In etwa so:


```
KochThread koeche[]=new KochThread[upb_chefs];
for (int i=0;i<upb_chefs;i++) {
  koeche[i]=new KochThread();
  koeche[i].start();
}

for (current_state=State.START ... State.END) {

  do {
    int ready=0;
    for (int i=0;i<upb_chefs;i++) {
       if (koeche[i].getState() == current_state) ready++;
    }
  while (ready != upb_chefs);

  for (int i=0;i<upb_chefs;i++) {
     koeche[i].setState(current_state+1);
  }

 } // next state
```

So in etwa. Bleibt "nur" noch das Problem, wie man ohne notify/wait den Koch-Thread dazu bringt sich nach erreichen des nächsten States schlafen zu legen.

Bernd


----------



## tuttle64 (15. Okt 2012)

Bernd Hohmann hat gesagt.:


> Vielleicht hilft (wie in einer Großlüche auch) ein "Maître de Cuisine".



Ich habe eine ähnliche Lösung gewählt, nur statt einer for-schleife mit einer while. Das Problem "nächsten States schlafen zu legen": Nach jedem State geht der Thread in eine Endlosschleife, die "wartet", bis alle Threads einen bestimmten Status erreichen.


----------



## Bernd Hohmann (15. Okt 2012)

tuttle64 hat gesagt.:


> Nach jedem State geht der Thread in eine Endlosschleife, die "wartet", bis alle Threads einen bestimmten Status erreichen.



Das mit der Endlosschleife ist eher eine schlechte Konstruktion, die wird dem Dozenten nicht gefallen.

Klassisch wegprogrammiert würde man statt der Endlosschleife ein .wait() nehmen und beim setzen des States ein .notify() auf das jeweilige Objekt was man als Lock nimmt absetzen damit er aus wait() herausfällt. Ich hatte einen Link mit höher abstrahierten Alternativen gepostet.

Vielleicht will der Aufgabensteller auch auf eine BlockingQueue hinaus: Galileo Computing :: Java ist auch eine Insel – 13.7 Queues (Schlangen) und Deques

Bernd


----------

