Threads Thread wait/notify

giggo

Mitglied
Hallo Leute,

hab folgendes Problem: es sollen vier Spieler (Threads) abwechselnd (gleiche reihenfolge) auf ein Kartendeck zugreifen und dabei ein Karte abheben und sobalt sie vier in der Hand also wenn sie die fünfte ziehen eine wieder ablegen. Das Ziel ist es vier von einem Typ zu haben(Quartet).

Mir ist leider nicht ganz klar wie ich die Threads nun am geschicktesten synchronisiere. Mein Ansatz ist sie in eine LinkedList zu geben und immer einen Thread zu nehmen in einer Runde spielen zu lassen und ihn dann wieder hinten rein zu hängen. Mir ist aber nicht klar ob das so überhaupt funktionieren kann. Vorallem ist mir nicht ganz klar was ich synchronized machen soll wenn ich so und so nur einem Thread zur gleichen Zeit erlaube zu spielen.

Hier mal was ich habe (ohne triviale Klassen).

Player:

Java:
import java.util.ArrayList;
import java.util.Collections;

public class Player extends Thread {

	private ArrayList<Card> cards = new ArrayList<Card>();
	private Pile pile;
	private Card preferredCard1;
	private Card preferredCard2;

	public Player(String name, int p1, int p2, Pile p) {
		super(name);
		this.preferredCard1 = new Card(p1);
		this.preferredCard2 = new Card(p2);
		this.pile = p;
		this.start();
	}

	

	public void play() {
		run();
	}

	public void run()  {
		System.out.println(this.getName()+ " started!");
		
		while(true) {		
	                //ich wollte hier einfach wait() machen und darauf warten notify augerufen wird
			draw(pile.getCard());
			if(checkQuartet()) return;
			pile.addCard(discard());
			System.out.println(this.getName()+showHands());
			
		}
	}

	private String showHands() {
		return cards.toString();
	}

	public void draw(Card e) {
		cards.add(e);
	}

	public Card discard() {
		if (cards.size() < 5)
			return null;
		for (Card e : cards)
			if (!e.equals(preferredCard1) && !e.equals(preferredCard2)) {
				cards.remove(e);
				return e;
			}
		Collections.sort(cards);
		if (cards.get(0).equals(cards.get(2)))
			return cards.remove(4);
		return cards.remove(0);
	}

	public boolean checkQuartet() {
		if (cards.size() < 4)
			return false;
		Collections.sort(cards);
		if (cards.get(0).equals(cards.get(3)))
			return true;
		if (cards.size() > 4 && cards.get(1).equals(cards.get(4)))
			return true;
		return false;
	}

}


Game:

Java:
import java.util.LinkedList;

public class Game extends Thread {
	private Pile pile;
	private LinkedList<Player> players = new LinkedList<Player>();
	
	public Game() {
		pile = new Pile();
		for(int i = 0; i<4; i++)
			players.add(new Player("Player "+i,i,i+4, pile ));		
	}	
	// Hier hatte ich dann noch ne schleife im run die die Threads mittels Notify anstossen sollte


	
	
}

Karten

Java:
public class Card implements Comparable<Card> {
	private int type;
	
	public Card(int type) {
		this.type = type;
	}
	
	public int getType() {
		return type;
	}

	
	public int compareTo(Card e) {
		Integer a = new Integer(type);
		Integer b = new Integer(e.getType());
		return a.compareTo(b);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + type;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Card other = (Card) obj;
		if (type != other.type)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "" + type;
	}

Pile (Kartendeck)

Java:
import java.util.Collections;
import java.util.LinkedList;

public class Pile {
	private LinkedList<Card> pile = new LinkedList<Card>();

	public Pile() {
		for (int i = 0; i < 32; i++)
			this.addCard(new Card(i % 8));
		Collections.shuffle(pile);
	}

	public synchronized void addCard(Card e) {
		if(e!=null)
		pile.addLast(e);
	}

	public synchronized Card getCard() {
		System.out.println(pile.size());
		return pile.removeFirst();
	}

	public int size() {
		return pile.size();
	}

}

also wenn ihr mir mal sagen könntet ob mein ansatz so richtig ist wär ich euch schon dankbar ;)

wenn ihr noch informationen braucht schreibts bitte
 

D4rkscr43m

Bekanntes Mitglied
Ohne den Code durchgegangen zu sein mal die Frage: Warum Threads, wenn diese NACHEINANDER Arbeiten sollen?
Das macht für mich wirklich keinen Sinn. Vielleicht sieht man das aber auch im Code, dann verzeihe mir meinen "Spam" ^^
 
T

Trolllllll

Gast
Das ist eine gute Frage, warum man für sowas Threads braucht, aber du könntest eine Variable machen, in der immer der nächste Thread drinnensteht der drann ist, ändern darf ihn nur der aktuelle Thread, die anderen Threads warten, bis ihre id in dieser Variable stehen, machen ihren zug und erhöhen dann die Variable (der letzte setzt sie wieder auf 0)
 

giggo

Mitglied
es ist mir klar das Threads schwachsinn sind aber ich hab die aufgabe ja nicht erstellt und die ist threads für die spieler zu verwenden... dazu kommt noch das es so und so nicht terminert, trotzdem muss die synchronisation aber machbar sein
 
T

Trolllllll

Gast
...aber du könntest eine Variable machen, in der immer der nächste Thread drinnensteht der drann ist, ändern darf ihn nur der aktuelle Thread, die anderen Threads warten, bis ihre id in dieser Variable stehen, machen ihren zug und erhöhen dann die Variable (der letzte setzt sie wieder auf 0)
Was spricht gegen diese idee?
Galileo Computing :: Java ist auch eine Insel – 14.5 Synchronisation über kritische Abschnitte

Galileo Computing :: Java ist auch eine Insel – 14.6 Synchronisation über Warten und Benachrichtigen
 

giggo

Mitglied
ja wait/notify war mein gedanke ;) aber ich bekomm dann immer die IllegalMonitorStateException die auch in Java ist auch eine Insle genau erklärt wird aber ich blick da dann nicht mehr ganz durch wo ich mein synchronized hinmachen muss...
 
S

SlaterB

Gast
erkäre doch in Worten, was wait/ notify ist, wie kann es eine Unklarheit zum Synchronized geben?
jeder andere könnte das natürlich auch wiederholen, aber wie sollte etwas besseres als das Lehrbuch, die perfekte Form herauskommen?

die kannst die Arbeit in getCard() stecken, die ist eh schon synchronized, auf das gemeinsame Objekt zu synchronisieren ist wichtig,
da können wait/ notify stehen, die Idee ist gegeben, habe ich gerade auch kurz ausprobiert,
wichtig ist noch darauf zu achten, bei ausgeschiedenen Threads keine Lücke zu lassen, nicht dass alle auf den warten der schon fertig ist und nie mehr kommt ;)

ob es keine Quartetts gibt ist eine Frage, bei mir gerade nicht so das Problem, zumal du ja bereits schon das Halten bestimmter Karten eingebaut hast, das wirkt sich positiv aus,
notfalls geht es halt nicht in manchen Konstellationen, dann vielleicht noch Shuffle alle x Runden einbauen
 

giggo

Mitglied
Da nachdem jeder Spieler vier Karten gezogen hat nur noch 16 im Stappel sind passiert folgendes: Ein Spieler nimmt ein Karte und un dlegt sie unten auf den Stappel damit bekommt er nach vier runden wieder die gleiche Karte. Damit bekommt jeder Spieler nur zugriff auf genau acht Karten. Aber du hast recht ein shuffel schaft abhilfe ;)

es würde mir mal helfen wenn mir jemand genau erklären könnte was genau mit monitor gemmeint ist. Ich meine getCard synchronized zu machen hilt mir ja noch nicht dabei das die threads eine bestimmte reihenfolge einzuhalten.

also ich seh grad ich hab das auch falsch verstanden wie es genau funktioniert.

ich habe gedacht ein wait() läst den thread warten und mit notify kann ich den thread wieder anstossen

es ist aber so das ich mit notify den ersten thread wieder anstosse welcher im synchronized bereich wartet

ist das so?
 

D4rkscr43m

Bekanntes Mitglied
das Notify geht immer an den, bei dem es aufgerufen wird.
bsp:
ThreadA:
Java:
void doSmth() {
  for(int i = 0; i < 3; i++) {
    try {
      wait();
    } catch (Exception e) {}
    System.out.println(i);
  }
}
ThreadB:
Java:
void doSmthElse() {
  Thread threadA = ...//Erzeuge ThreadA und lasse dort die soSmth()-Methode laufen
  threadA.notify(); // Hierdurch wird der threadA wieder freigegeben und es kommt zur Ausgabe von 0
}

du musst also notify auf dem Objekt aufrufen, auf dem auch wait aufgerufen wurde.
 
S

SlaterB

Gast
Da nachdem jeder Spieler vier Karten gezogen hat nur noch 16 im Stappel sind passiert folgendes: Ein Spieler nimmt ein Karte und un dlegt sie unten auf den Stappel damit bekommt er nach vier runden wieder die gleiche Karte.
auch nicht zwingend wenn noch gute Karten gehalten werden, aber möglich natürlich,

ist so,

Synchronisation bei getCards() liefert gegenseitigen Ausschluss und alle Threads können an diesem einen Monitor warten wenn sie nicht dran sind und aufgeweckt werden, notifyAll() hier wichtig
 

Oben