Thread
Programm innerhalb eines reserviertem Speicherbereiches des Betriebssystems.
Es wird Anweisung nach Anweisung durchgeführt. Unterschiedliche Prozesse
besitzen unterschiedliche Speicherbereiche für ihre Variablen.
In Java können mehrere Prozesse gleichzeitig gestartet werden.
Können nur innerhalb eines Prozesses laufen. Unterschiedliche Threads
eines Prozesses können auf den Speicherbereich einer Variablen eines
Prozesses zugreifen = gleichzeitiger Zugriff auf dieselbe Variable möglich!!
Das muß natürlich geregelt abgehen!(synchronized)
Es können mehrere Threads innerhalb eines Prozesses gestartet werden.
= Multitasking.
Wozu braucht man das?:
-
Ein Programm soll nicht warten, bis das eine Schleife beendet wurde
(Animation, ...)
-
Ein Programm soll nicht warten, bis das eine Anfrage beantwortet wurde
(Druck, Datei laden, mehrere Anwender gleichzeitig...)
-
Teile eines Programmes sollen zeitlich unabhängig miteinander
interagieren (Netzwerk, KI..)
-
Werden mehrere unterschiedliche Resourcen(Festplatte,... ) und Prozessoren
genutzt, können Aufgaben eines Programmes verteilt werden, was die
Geschwindigkeit eines Programmes erhöht
Ist nur ein Prozessor vorhanden, ist das parallele Ausführen mehrerer
Programme nicht möglich.Daher wird zwischen den einzelnen Theads hin und
hergeschaltet (schedule)
Ein nicht beendeter Thread läuft nach Programmbeendigung weiter!! Endet
ein Thread mit Programmende, spricht man von einem Dämon.
Thread anwenden:
- Typ Runable festlegen:
a) Entweder wird dafür das Interface API: java.lang.Runable
verwendet, mit implements Runable()
b) oder die Klasse API: java.lang.Thread, die
Runable implementiert, wird geerbt: mit extends Thread
- Thread als Dämon im Konstruktor des Threads definieren: setDaemon(
true );
- Thread anmelden, damit er zur Verfügung steht: start()
- Methode run() des aktuellen oder eines gestarteten Threads
aufrufen, damit der Thread seine Tätigkeit beginnt. Sie entspricht der
Methode paint() einer GUI. Alles was eben als eigenes Programm laufen soll,
wird hier eingetragen!
- Greifen mehrere Threads auf ein Attribut eines Objektes zu, und mindestens
ein Thread kann dieses Attribut ändern, muß der Zugriff geregelt
(synchronisiert) werden:
a) die Funktion mit synchronized versehen oder
b) den kritischen Bereich:(monitoring)
|
MyObject opj = new MyObject();
synchronized( opj )
{
opj.methode();
}
|
Achtung vor Deadlooks!!! = Einer wartet auf den anderen wartet auf den einen
........
Will man einen geordneten Ablauf der Kommunikation unter den einzelnen Threads
ist es sinnvoll diese wie in einer Disskussion zu regeln:
Beispiel:
2 Threads verwenden ein DatenObjekt obj. Wenn der Erzeuger des DatenObjektes
fertig ist, kann der Konsument mit diesem DatenObjekt weitermachen. Daher
erhält zuerst der Erzeuger den Monitor und dann der Konsument. Damit
wird die Reihenfolge festgelegt.
Nur der aktive Thread, daher derjenige Thread, der auf das DatenObjekt wartet
(= Konsument), kann seinen Monitor an dem Erzeuger freigeben um dann mit dem
gelieferten DatenObjekt weiterarbeiten zu können!!!! (sonst sinnlos !!)
a) Ein Thread der ein DatenObjekt senden will = Erzeuger , meldet das mit
notify() in der synchronizierten Methode an!
|
class Lieferant implements Runable{
DatenObject opj = new DatenObject();
synchronized( opj )
{
opj.methode();
obj.notify();
}
}
|
Sollen alle Threads benachrichtigt werden: notifyAll()
b) Ein Thread der dieses DatenObjekt erhalten will = Konsument , meldet das
mit wait().
|
class Konsument implements Runable{
DatenObject opj = new DatenObject();
synchronized( opj )
{
opj.methode();
try {
obj.wait();
} catch ( InterruptedException e ) {}
}
}
|
- Leider können Threads jederzeit auf elementare Variablen zugreifen.
Es ist nicht gesichert, ob der Wert der Variablen fertig geschrieben ist,
wenn die Variable in Teilen (Register) oder innerhalb einer Schleife geändert
wird. Durch setzen von volatile bei Deklarierung der Variable,
wird jeder aktuelle Wert sofort geschrieben.
- Kann erst weitergemacht werden, wenn eine Funktion eines anderen Threads
beendet wurde, dann muß derjenige, der darauf wartet, dies mit
join() auf diesen Thread bekanntgeben
- Aktive Threads können durch Aufruf von Thread.sleep(zeit),
in der Methode run, verlangsamt werden. (Berechnung ist schneller als die
Bildschirmdarstellung,...)
- Ein Thread wird intern nach Durchlaufen aller Anweisungen oder extern durch
interrupt() und Abfragen dieses Wertes durch isInterrupted()
in der Methode run() beendet!
- wurden Threads verwendet, die keine Dämonen sind und sie sollen nach
Programmende nicht mehr laufen: System.exit()!
Zeitbasierende Wiederholungen werden über die lasse API:
java.util.TimerTask durchgeführt