# Thread abwechseln (Grundidee)



## MAIAarts. (14. Apr 2008)

Guten Abend,

ich möchte es in Java realsieren, dass sich zwei Threads abwechseln und unterbrechen. Nach der Unterbrechnung soll dann immer der andere Thread einen Teil seiner Arbeit tun, nur um wieder unterbrochen zu werden. Meine Idee füge ich unten ein.
Bei Fragen zum Code stehe ich natürlich bereit. Vielleicht hat jemand eine Idee, wie ich die Threads abwechseln kann.


```
public class Hauptt
{
	public static void main(String[] args) 
	{	
		//-- Thread beides in einer While-Schleife --
		ABCThread ABC1 = new ABCThread(true); 
		ABCThread ABC2 = new ABCThread(false); 
		new Thread(ABC1).start();
		new Thread(ABC2).start();
       }
}
```


```
public class ABCThread 
	implements Runnable
	
{
	private char kzeichen = 'a';
	private char gzeichen = 'A';



	
	public boolean grossklein;
	//Variable für Isinterrupted
	private static boolean isDran=false;

	public ABCThread(boolean grossklein)
	{
		this.grossklein=grossklein;
	}
	
	public void run()
	{

		if(grossklein)
		while (!Thread.currentThread().isInterrupted() )
		{
			for (int i= 0;i<26;i++)
			{
				try
				{
				
				System.out.print(gzeichen);
				
				gzeichen++;
				
				Thread.sleep(100);
				Thread.yield();
				Thread.currentThread().interrupt();
				
				}
				catch (InterruptedException o){}
			}
		}

		if(!grossklein)
		while (!Thread.currentThread().isInterrupted() )
		{
			for (int j= 0;j<26;j++)
			{
				try
				{
				
				System.out.print(kzeichen);
				kzeichen++;
				
				Thread.sleep(100);
				System.out.print(" ");
				Thread.yield();
				Thread.currentThread().interrupt();
				}
				catch (InterruptedException o){}
			}
		}
	}
}
```

Nicht erschrecken, falls es unüberischtlich aussehen sollte, es ist zweimal die gleiche Methode, Unterschied sind nur Groß- bzw. Kleinbuchstaben.

Leider klappt es nicht mehr, seitdem ich die Isinterrupted Methode benutze. Vorher wechseln sich die Threads ab, wie sie gerade Lust haben.


Bis Dann.


MAIAarts.


----------



## André Uhres (15. Apr 2008)

Das geht mit Hilfe der Synchronisation. Siehe auch: Java und die Synchronisation

```
package demo; 
/* 
* Hauptt.java 
*/ 
public class Hauptt { 
    public Hauptt() { 
        ABCThread ABC1 = new ABCThread(true, this); 
        ABCThread ABC2 = new ABCThread(false, this); 
        new Thread(ABC1).start(); 
        new Thread(ABC2).start(); 
    } 
    public static void main(final String[] args) { 
        new Hauptt(); 
    } 
} 
class ABCThread implements Runnable { 
    private char kzeichen = 'a'; 
    private char gzeichen = 'A'; 
    private boolean gross; 
    private Hauptt abc; 
    public ABCThread(final boolean gross, final Hauptt abc) { 
        super(); 
        this.gross = gross; 
        this.abc = abc; 
    } 
    public void run() { 
        for (int i = 0; i < 26; i++) { 
            synchronized (abc) { 
                if (gross) { 
                    System.out.println(gzeichen); 
                    gzeichen++; 
                    delay(100); 
                } else { 
                    System.out.println(" " + kzeichen); 
                    kzeichen++; 
                    delay(50); 
                } 
                abc.notify();//Nachdem der andere Thread geweckt wurde,... 
                try { 
                    abc.wait();//entschläft der laufende Thread und wartet, um später geweckt zu werden. 
                } catch (InterruptedException e) { 
                } 
                //Die zwei Threads werden folglich abwechselnd durchgeführt. 
            } 
        } 
    } 
    private void delay(final long millis) { 
        try { 
            Thread.sleep(millis); 
        } catch (InterruptedException o) { 
        } 
    } 
}
```


----------



## tfa (15. Apr 2008)

Hier noch eine Version mit Lock und Condition:

```
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ABCThread implements Runnable {

	private static Lock lock = new ReentrantLock();
	private static Condition condition = lock.newCondition();

	private char kzeichen = 'a';
	private char gzeichen = 'A';

	public boolean grossklein;

	public ABCThread(boolean grossklein) {
		this.grossklein = grossklein;
	}

	public void run() {

		if (grossklein) {
			for (int i = 0; i < 26; i++) {

				try {
					lock.lock();
					condition.await();
					System.out.print(gzeichen);
					Thread.sleep(100);
					gzeichen++;
				} catch (InterruptedException o) {
				} finally {
					lock.unlock();
				}
			}
		}

		if (!grossklein)

			for (int j = 0; j < 26; j++) {
				try {
					lock.lock();
					condition.signal();
					System.out.print(kzeichen);
					kzeichen++;
				} finally {
					lock.unlock();
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.print(" ");
			}

	}

	public static void main(String[] args) {
		//-- Thread beides in einer While-Schleife -- 
		ABCThread ABC1 = new ABCThread(true);
		ABCThread ABC2 = new ABCThread(false);
		new Thread(ABC1).start();
		new Thread(ABC2).start();
	}
}
```

So ist das allerdings noch ein wenig buggy, da die Threads manchmal aus dem Takt kommen können, d.h.
einer ist zweimal hintereinander dran.  Eigentlich bräuchte man zwei Conditions um das zu verhindern.

Kann es eigentlich sein, dass sich Threading-Fragen in letzter Zeit häufen?


----------



## Guest (15. Apr 2008)

Ist stoff einer Vorlesung. Soweit ich das verstanden habe sollte man das synchronized in unserer Aufgabenstellung noch nicht nutzen, erst in der nächsten ist das gefordert. 
Gibt es keine Möglichkeit es mit einer Boolean Variable und, der einfachen Frage ob der Thread unterbrochen ist, schaffen?

Mit dem Synchronized habe ich es schon versucht. Schaue mr die beiden Lösungen natürlich an.


----------



## André Uhres (15. Apr 2008)

tfa hat gesagt.:
			
		

> Hier noch eine Version mit Lock und Condition..


Für diese  einfache Aufgabenstellung empfehle ich eher *synchronized* zu verwenden :wink:


----------



## tfa (15. Apr 2008)

André Uhres hat gesagt.:
			
		

> Für diese  einfache Aufgabenstellung empfehle ich eher *synchronized* zu verwenden :wink:


Ich rate meistens von *synchronized* ab - komplett. Das ist mir einfach zu "low-level". Das Angebot von java.util.concurrent ist so groß, dass für jeden Anwendungsfall was dabei sein sollte. Und die Wahrscheinlichkeit, das es dann wirklich funktioniert, ist damit wesentlich größer, als wenn man alles von Hand synchronisieren muss (bei mir jedenfalls).


----------



## André Uhres (15. Apr 2008)

tfa hat gesagt.:
			
		

> Ich rate meistens von *synchronized* ab - ..die Wahrscheinlichkeit, das es dann wirklich funktioniert, ist damit wesentlich größer..


Aha, deshalb funktioniert deine Version nicht  :lol:


----------



## tfa (15. Apr 2008)

Erwischt! 
Aber ich hab ja schon gesagt, wie man es reparieren kann.

PS: Dein Programm terminiert übrigens nicht. :lol:


----------



## André Uhres (15. Apr 2008)

tfa hat gesagt.:
			
		

> ich hab ja schon gesagt, wie man es reparieren kann.


Warum machst du's nicht einfach?



			
				tfa hat gesagt.:
			
		

> Dein Programm terminiert übrigens nicht.


Deins auch nicht  :lol:


----------



## Guest (15. Apr 2008)

Es lief einmal durch, erst die großen Buchstaben dann die kleinen. Dann veruschte ich die Threads abzuwechseln, seitdem muss ich es von Hand stoppen. Ich Frage mich auch, wieso Fragezeichen ausgegeben werden, wo ist der Teil des Codes, welcher diesen Fehler erzeugt (Fehler ist vielleicht falsch gesagt, gemeint ist unerwünschten Effekt).


----------



## MAIAarts. (15. Apr 2008)

Es lief einmal durch, erst die großen Buchstaben dann die kleinen. Dann veruschte ich die Threads abzuwechseln, seitdem muss ich es von Hand stoppen. Ich Frage mich auch, wieso Fragezeichen ausgegeben werden, wo ist der Teil des Codes, welcher diesen Fehler erzeugt (Fehler ist vielleicht falsch gesagt, gemeint ist unerwünschten Effekt).

Gut, dass ich als Gast schreiben kann. Nervt mich gerade. 
Ich kann mir einfach nicht vorstellen solch einen hohen Schwierigkeitsgrad mit dieser Aufgabe gewählt zu haben. Immerhin steht sie unter Übung 1.

So hier ist eine Variante nahezu ähnlich, gibt allerdings nur die ersten beiden Buchstaben aus: einmal das kleine "a" und einmal das große "A". Dies sollte aber bis zum Z durchgezogen werden, und am besten dann immer weiter.


```
public class ABCThread 
	implements Runnable
	
{
	private char kzeichen = 'a';
	private char gzeichen = 'A';



	
	public boolean grossklein;
	//Variable für Isinterrupted
	private static boolean istDran=false;

	public ABCThread(boolean grossklein)
	{
		this.grossklein=grossklein;
	}
	
	public void run()
	{

		if(grossklein)
			//if (istDran)
		for(int ei = 0;!Thread.currentThread().isInterrupted();ei++ )
		{
			for (int i= 0;i<26 && istDran == true;i++)
			{
				try
				{
				
				System.out.print(gzeichen);
				
				gzeichen++;
				
				Thread.sleep(100);
				Thread.yield();
				istDran= false;
				Thread.currentThread().interrupt();
				}
				catch (InterruptedException o){}
				
			}
			
		}

		if(!grossklein)
			//if (!istDran)
		for (int ej = 0;!Thread.currentThread().isInterrupted();ej++ )
		{
			for (int j= 0;j<26 && istDran==false;j++)
			{
				try
				{
				System.out.print(kzeichen);
				
				kzeichen++;
				
				Thread.sleep(100);
				System.out.print(" ");
				Thread.yield();
				istDran= true;
				Thread.currentThread().interrupt();
				}
				catch (InterruptedException o){}
				
			}
			
		}
	}
}
```

Vielleicht ist mein Problem, dass meine Threads weiter ruhen, nachdem sie einmal aufgerufen wurden.


----------



## tfa (15. Apr 2008)

André Uhres hat gesagt.:
			
		

> Warum machst du's nicht einfach?


Ich muss leider noch ein bisschen arbeiten hier....


----------



## tfa (15. Apr 2008)

Okay, ich hab die Mittagspause vorgezogen.

```
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ABCThread implements Runnable {

	private static Lock lock = new ReentrantLock();
	private static Condition ping = lock.newCondition();
	private static Condition pong = lock.newCondition();

	private char kzeichen = 'a';
	private char gzeichen = 'A';

	public boolean grossklein;

	public ABCThread(boolean grossklein) {
		this.grossklein = grossklein;
	}

	public void run() {

		if (grossklein) {
			for (int i = 0; i < 26; i++) {

				try {
					lock.lock();
					ping.await();					
					System.out.print(gzeichen);					
					gzeichen++;
					pong.signal();
					Thread.sleep(10);
				} catch (InterruptedException o) {
				} finally {
					lock.unlock();
				}
			}
		}

		if (!grossklein)

			for (int j = 0; j < 26; j++) {
				try {
					Thread.sleep(10);
					lock.lock();					
					ping.signal();
					System.out.print(kzeichen);
					kzeichen++;	
					pong.await();					
				}
				catch(InterruptedException x){}
				finally {
					lock.unlock();
				}				
				System.out.print(" ");
			}
	}

	public static void main(String[] args) throws Exception {		
		for (int i=0; i<1000; i++){
			System.out.printf("%4d: ",i);
			ABCThread ABC1 = new ABCThread(true);
			ABCThread ABC2 = new ABCThread(false);
			Thread t1 = new Thread(ABC1);
			Thread t2 = new Thread(ABC2);
			t1.start();
			t2.start();
			t1.join();
			t2.join();
			System.out.println();
		}
	}
}
```
Und jetzt kommst du!


----------



## André Uhres (15. Apr 2008)

tfa hat gesagt.:
			
		

> Ich muss leider noch ein bisschen arbeiten hier....


Wenn die Korrektur aufwendiger ist als dein sinniges Geschreibsel,
dann bleiben wir wohl doch lieber bei *synchronized*  :lol:


----------



## Wolfram (15. Apr 2008)

MAIAarts. hat gesagt.:
			
		

> Ich kann mir einfach nicht vorstellen solch einen hohen Schwierigkeitsgrad mit dieser Aufgabe gewählt zu haben. Immerhin steht sie unter Übung 1.



Das liegt wahrscheinlich daran, dass etwas *SEHR* ähnliches bereits irgendwo auf den Folien steht, in denen Du nur ein paar Zeilen ändern musst. Die erwarten eigentlich nicht, dass Du das Rad neu erfindest - wohl aber, dass Du die Vorlesung nacharbeitest. Als ich das nach einiger Zeit begriffen hatte, gingen mir die Übungen damals unglaublich viel leichter von der Hand. 

Wobei es natürlich viel lehrreicher ist, das Rad neu zu erfinden. 

Meine Lösung war zu ähnlich, aber wenn alle eine posten, mache ich mit 

Andres Lösung braucht vermutlich noch ein notify() nach der for-Schleife, um zu terminieren. Das ist dann insgesamt ein notify() zu viel, genau wie zu Anfang eines verloren geht, weil der andere Thread noch nicht wartet, aber das macht ja nix. 


```
package abwechseln;

class ABCThread extends Thread {
    
    final static Object lock=new Object(); // Klassenvariable, um alle threads drauf zu synchronisieren.
    
    char zeichen;  // Objektvariablen, pro Thread
    
    ABCThread(boolean gk) {
        this.zeichen= gk ? 'A' : 'a';
    }

    @Override
    public void run() {
        synchronized(lock) {
            
            for (int i=0; i<26; i++, zeichen++) {            
                lock.notify();
                try { lock.wait(); } catch (InterruptedException e) {}
                
                System.out.print(zeichen);
            }   
            lock.notify();
        }
    }
}

public class Main {
    public static void main(String[] args) {  
        ABCThread ABC1 = new ABCThread(true);
        ABCThread ABC2 = new ABCThread(false);
        ABC1.start();
        ABC2.start();
    }
}
```


----------



## tfa (15. Apr 2008)

André Uhres hat gesagt.:
			
		

> Korrektur


Siehe oben.


> sinniges Geschreibsel


Wenn du anderer Meinung bist, kannst du gerne dagegen _argumentieren_. So nicht!


----------



## André Uhres (15. Apr 2008)

tfa hat gesagt.:
			
		

> _argumentieren_


Ich hab eigentlich schon mit "aufwendiger" argumentiert,
das hast du wohlweißlich bei deinem Zitat weggelassen :lol:
Hier suchen wir eine möglichst einfache Lösung und du kommst mit sowas  :shock:


----------



## MAIAarts. (15. Apr 2008)

So, werde es direkt testen, und durcharbeiten. Es gibt allerdings eine Unklarheit:


```
ABCThread(boolean gk) {
        this.zeichen= gk ? 'A' : 'a';
    }
```

Verstehe diese Zeile nicht die mit  "this" beginnt.


So hat die Aufgabestellung ausgesehen:

Aufgabe 3 (Abwechseln erzwingen)
Wie können Sie erreichen, dass die Threads klein und groß abwechselnd an die Reihe kommen? 
Anders ausgedrückt, erzwingen Sie, dass die Ausgabe der beiden Threads klein und groß so 
aussieht: 
entweder aAbBcCdDeEfF...wWxXyYzZ    oder       AaBbCcDdEeFf....WwXxYyZz.
Hinweis: Führen Sie eine Kontrollvariable istDran ein, die festhält ob der Thread klein oder 
der Thread groß an der Reihe ist.


----------



## tfa (15. Apr 2008)

MAIAarts. hat gesagt.:
			
		

> this.zeichen= gk ? 'A' : 'a';


Bedeutet hier das gleiche wie:

```
if (gk) {
   this.zeichen = 'A';
}
else {
   this.zeichen = 'a';
}
```


----------

