Threads Threads warten lassen

w00t

Aktives Mitglied
Hallo,

ich habe ein Problem und weiß nicht genau woran das liegt. Vielleicht steh ich einfach auf dem Schlauch.

Folgendes ist gegeben:

Eine Abstrakte Klasse die von 3 anderen Klassen benutzt wird:

Java:
public abstract class myAbstract implements Runnable {
	final Lock lock = new ReentrantLock();
	final Condition atPersist = this.lock.newCondition();
	protected static boolean atPersistBool = false;


	[...]

	public final void run(){
		this.lock.lock();
		while(myAbstract.atPersistBool){
			this.atPersist.await();
		}
		myAbstract.atPersistBool = true;
		[...]
		this.persist();
		[...]
		myAbstract.atPersistBool = false;
		this.atPersist.signallAll();
	}

}

Die 3 Klassen werden gleichzeitig gestartet, machen dann ein wenig datensammelei (was je nachdem unterschiedlich schnell läuft) und dann soll das alles in die SQLite DB geschrieben werden. Das Problem ist, es dürfen in SQLite nicht mehrere Transaktionen gleichzeitig gemacht werden. Heißt für mich: Sobald es ans persistieren geht, muss der erste das für die anderen blocken und das dann - wenn er fertig ist - wieder freigeben, so das der nächste [Thread] das selbe machen kann.

Aktuell passiert folgendes:
Thread 1: kommt an, merkt das noch alles frei ist, ist am abarbeiten.
Thread 2: kommt an, merkt das er warten muss.
Thread 3: kommt an, merkt das er warten muss.
Thread 1: ist fertig.

Das war es, Thread 2 und 3 bekommen nicht gesagt das sie weiter machen dürfen. Wieso nicht? Wo ist der denkfehler?

Den Code habe ich übernommen aus der JavaInsel: Galileo Computing :: Java ist auch eine Insel – 14.6 Synchronisation über Warten und Benachrichtigen

Was ich versucht habe:
Mein Gedanke war, das es vielleicht daran liegt das alle ihr eigenes "lock" usw. bauen. Also habe ich die (lock, atPersist) einfach mal static gemacht.

Java:
public abstract class myAbstract implements Runnable {
	final static Lock lock = new ReentrantLock();
	final static Condition atPersist = myAbstract.lock.newCondition();
	protected static boolean atPersistBool = false;


	[...]

	public final void run(){
		myAbstract.lock.lock();
		while(myAbstract.atPersistBool){
			myAbstract.atPersist.await();
		}
		myAbstract.atPersistBool = true;
		[...]
		myAbstract.persist();
		[...]
		myAbstract.atPersistBool = false;
		myAbstract.atPersist.signallAll();
	}

}

Ergebnis:
Thread 1: kommt an, merkt das noch alles freit ist, ist am abarbeiten. Ist fertig.

Das wars. Thread 2 und 3 kommen nicht einmal dahin, was ich nicht wirklich verstehe. Bin gerade das erste mal damit konfrontiert das Threads aufeinander warten müssen, und suche daher die beste Lösung. Da scheint es ja viele zu geben.
 
Ich habe jetzt einmal etwas anderes getestet:
Java:
public abstract class myAbstract implements Runnable {
	protected static boolean atPersistBool = false;
	private static String test = new String();


	[...]

	public final void run(){
		synchronized (ACollector.test) {
			while(myAbstract.atPersistBool){
				myAbstract.test.wait();
			}
			myAbstract.atPersistBool = true;
			[...]
			this.persist();
			[...]
			myAbstract.atPersistBool = false;
			myAbstract.test.notify();
		}
	}

}

Das klappt. Die Frage ist nur: Ist das elegant? Wieso funktioniert das hier und das andere nicht?
 
Diese while-Schleife brauchst du mit dem Synchronized block nicht mehr!
Dieser regelt das allein. Du erstellst auf das test-Objekt einen Lock.
Alle Threads, die auch einen Synchronized-Block auf das selbe Objekt machen wollen,
warten, bis auf dieses Objekt notify aufgerufen wird.

Im Grunde würde also auch folgender Code funktionieren:

Java:
public abstract class myAbstract implements Runnable {
    private static Object lockObject = new Object();
      [...]
     public final void run(){
        synchronized (ACollector.lockObject) {
            [...]
            this.persist();
            [...]
            lockObject.notify();
        }
    }
 }
 
Zuletzt bearbeitet:
Nunja, von deiner Methode habe ich das erste mal gesehen!
Ich habe bei Thread-Synchronisierung immer diese Synchronized Blöcke verwendet.

Ich dachte das wäre Standard.

Theoretisch könntest du das noch verschönern, indem du auf deine Datenbank den Lock legst.

quasi mit [c]synchronized(databaseConnection){[/c]

So würdest du wenn du auf verschiedene Datenbanken persistest, nicht immer alle anderen Datenbanken auch blockieren.
Aber ich weißt ja nicht wie dein DB-Verbindungscode aussieht.
 
Lokale Anwendung mit lokaler SQLite Datenbank. Also ist das nicht einmal notwendig. Aber behalte ich im Kopf für die Zukunft 🙂
 

Zurück
Oben