Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Allgemein Verständnissfrage zum Ablauf mehrerer Threads
Hallo
Ich habe gerade ein Verständnissproblem bzgl. dem Ablauf bei mehreren Threads
Angenommen ich habe eine Klasse "Test" aus der 2 Threads th1 und th2 gestartet werden,welches eigene Klassen sind. Wenn das Programm nun startet, wechseln sich dann nur die beiden Threads untereinander ab, oder wird die Hauptklasse Test dabei auch berücksichtigt? Ich hoffe meine Frage ist einigermaßen verständlich. Ich weiß natürlich, dass ich die Hauptklasse währenddessen weiter ausgeführt wird. zB bei einer GUI. Aber ich verstehe nicht ganz wie sich eben die Hauptklasse zu den Threads verhält bzgl. der Prozesszuordung( da ja keine echte Parallelität vorhanden ist, oder?)
Das ist so nicht ganz richtig.
Wenn du in deiner Testklasse einfach nur 2 Threads startest, kann die Klasse Test, sofern Sie nicht weiter gebraucht wird danach auch durchlaufen und beenden.
Damit hättest du nur die 2 Threads und der aufrufende Thread ist dann weg.
Da kann ich direkt mein Anliegen reinmischen. Sry für den Riesen-Beitrag der jetzt folgt, aber ich arbeite seit Tagen an dieser Sache. Meine Fragen stehen ganz unten.
Ich versuche das Kapitel zu Threads der Insel (9. Auflage) durchzuarbeiten und habe mir folgendes Beispiel vorgenommen: Es sollen "normale" Threads gestartet werden und parallel dazu zu jedem Thread ein Überwachungsthread, die mich über den Zustand der normalen Threads informieren. Die Idee ist, ein eigenes Tool zum Threads-Debuggen zu haben.
Konkret: Die Hauptklasse heißt "MultiTask" und der normale Thread ist in einer anderen Klasse "LaTarea". Dieser wird von der main von MultiTask gestartet und der Überwachungsthread ist in der Methode "wachen" von MultiTask.
LaTarea.run() tut nichts anderes als 10 Runden lang bischen 500 msek schlafen, und dann die Zeit, den Threadnamen, die vergangene Zeit und die Runde auszugeben.
Die Quelltextpassagen sehen so aus:
Java:
class LaTarea extends MultiTask implements Runnable {
@Override public void run() {
int runde=0;
String ichBinDer = Thread.currentThread().getName() ;
long jetztZeit = currentTimeMillis(), Anfang=jetztZeit, zeit = 0;
out.println( (jetztZeit%1000000)/1000f+"\t" + ichBinDer + " \t\t" + zeit);
while (runde < 10) {
try { TimeUnit.MILLISECONDS.sleep(500); } catch(InterruptedException e) { e.printStackTrace();}
jetztZeit=currentTimeMillis();
zeit = jetztZeit-Anfang;
out.println( (jetztZeit%1000000)/1000f+"\t" + ichBinDer + " \t\t" + zeit+ "\tRunde=" + (++runde));
}
}
}
Die main der Hauptklasse tut nichts anderes als erstens die Threads erzeugen, die Überwachung starten (dann kurz warten) und dann die Threads selbst. Die Überwachungsmethode enthält direkt den Threadquelltext als anonyme Klasse. Zuerst werden die Prioritäten so gesetzt, daß die Überwachungsmethode öfter läuft (oder das hätte ich gern). Dann, solange der überwachte Thread "checkingThread" nicht beendet ist, werden alle wichtigen Informationen in einem log gesammelt, wie zB Zustandsänderung und Zeitpunkt. Ganz zum Schluß wird dieser log ausgegeben.
Ein log wird angelegt, das alle gesammelten Informationen sammelt.
Java:
import static java.lang.System.*;
import java.lang.StringBuffer;
import java.util.concurrent.TimeUnit;
class MultiTask01 {
public static void main(String[] args) {
Thread t1 = new Thread( new LaTarea(), "LaTarea1" );
Thread t2 = new Thread( new LaTarea(), "LaTarea2" );
Thread t3 = new Thread( new LaTarea(), "LaTarea3" );
Thread t4 = new Thread( new LaTarea(), "LaTarea4" );
wachen(t1); wachen(t2); wachen(t3); wachen(t4);
try { Thread.sleep( 400 );} catch ( InterruptedException e){ e.printStackTrace();}
t1.start(); t2.start(); t3.start(); t4.start();
}
static void wachen(final Thread checkingThread) {
new Thread() {
@Override public void run() {
// Thread.currentThread().setPriority(MAX_PRIORITY);//MAX_PRIORITY=10
checkingThread.setPriority(MIN_PRIORITY);// MIN_PRIORITY=1
StringBuilder log = new StringBuilder(); //log zum Zustand von checkingThread
String ichBinDer = "Wächter von " + checkingThread.getName();
long jetztZeit = currentTimeMillis(), Anfang=jetztZeit, zeit = 0;
State zustand = checkingThread.getState();
log.append((jetztZeit%1000000)/1000f+ "\t" + ichBinDer+ "\t\t" + zustand+"\n");
while( zustand!=Thread.State.TERMINATED ) {
jetztZeit = currentTimeMillis();
State neuerZustand = checkingThread.getState();
if(neuerZustand!=zustand){
log.append((jetztZeit % 1000000) / 1000f ).append("\t").append(ichBinDer).append("\t\t").append(neuerZustand).append("\n");
zustand=neuerZustand;
}
}
if(!checkingThread.isAlive()) out.println(log+"\n");
}
}.start();
}
}
Die Ausgabe sieht bei mir (2-Core, 2,1 GHz, 32 Bit Vista) folgendermaßen aus:
Code:
run:
516.085 LaTarea2 0
516.194 LaTarea4 0
516.537 LaTarea3 0
516.756 LaTarea1 0
517.302 LaTarea2 1217 Runde=1
517.77 LaTarea3 1233 Runde=1
517.77 LaTarea4 1576 Runde=1
517.77 LaTarea1 1014 Runde=1
517.973 LaTarea2 1888 Runde=2
518.519 LaTarea2 2434 Runde=3
518.597 LaTarea3 2060 Runde=2
518.612 LaTarea1 1856 Runde=2
518.799 LaTarea4 2605 Runde=2
519.236 LaTarea2 3151 Runde=4
519.455 LaTarea4 3261 Runde=3
519.845 LaTarea3 3308 Runde=3
519.845 LaTarea1 3089 Runde=3
520.203 LaTarea2 4118 Runde=5
521.701 LaTarea1 4945 Runde=4
521.841 LaTarea4 5647 Runde=4
521.966 LaTarea3 5429 Runde=4
522.528 LaTarea1 5772 Runde=5
522.777 LaTarea3 6240 Runde=5
522.793 LaTarea2 6708 Runde=6
522.793 LaTarea4 6599 Runde=5
523.199 LaTarea1 6443 Runde=6
524.057 LaTarea1 7301 Runde=7
524.057 LaTarea3 7520 Runde=6
524.322 LaTarea2 8237 Runde=7
524.322 LaTarea4 8128 Runde=6
525.055 LaTarea3 8518 Runde=7
525.055 LaTarea1 8299 Runde=8
525.351 LaTarea2 9266 Runde=8
525.585 LaTarea4 9391 Runde=7
525.71 LaTarea1 8954 Runde=9
525.71 LaTarea3 9173 Runde=8
526.022 LaTarea2 9937 Runde=9
526.209 LaTarea3 9672 Runde=9
526.459 LaTarea1 9703 Runde=10
526.459 LaTarea4 10265 Runde=8
515.399 Wächter von LaTarea1 NEW
515.867 Wächter von LaTarea1 RUNNABLE
516.818 Wächter von LaTarea1 BLOCKED
517.083 Wächter von LaTarea1 TIMED_WAITING
517.551 Wächter von LaTarea1 RUNNABLE
517.832 Wächter von LaTarea1 TIMED_WAITING
518.378 Wächter von LaTarea1 RUNNABLE
518.659 Wächter von LaTarea1 TIMED_WAITING
519.299 Wächter von LaTarea1 RUNNABLE
519.891 Wächter von LaTarea1 BLOCKED
520.905 Wächter von LaTarea1 TIMED_WAITING
521.124 Wächter von LaTarea1 RUNNABLE
521.717 Wächter von LaTarea1 TIMED_WAITING
522.075 Wächter von LaTarea1 RUNNABLE
522.559 Wächter von LaTarea1 TIMED_WAITING
522.949 Wächter von LaTarea1 RUNNABLE
523.417 Wächter von LaTarea1 TIMED_WAITING
523.745 Wächter von LaTarea1 RUNNABLE
524.135 Wächter von LaTarea1 TIMED_WAITING
524.681 Wächter von LaTarea1 RUNNABLE
525.102 Wächter von LaTarea1 TIMED_WAITING
525.554 Wächter von LaTarea1 RUNNABLE
525.773 Wächter von LaTarea1 TIMED_WAITING
526.194 Wächter von LaTarea1 RUNNABLE
526.459 Wächter von LaTarea1 TERMINATED
527.364 LaTarea2 11279 Runde=10
515.414 Wächter von LaTarea2 NEW
515.867 Wächter von LaTarea2 RUNNABLE
516.21 Wächter von LaTarea2 TIMED_WAITING
517.037 Wächter von LaTarea2 RUNNABLE
517.302 Wächter von LaTarea2 TIMED_WAITING
517.661 Wächter von LaTarea2 RUNNABLE
518.004 Wächter von LaTarea2 TIMED_WAITING
518.331 Wächter von LaTarea2 RUNNABLE
518.612 Wächter von LaTarea2 TIMED_WAITING
519.049 Wächter von LaTarea2 RUNNABLE
519.299 Wächter von LaTarea2 TIMED_WAITING
519.86 Wächter von LaTarea2 RUNNABLE
520.235 Wächter von LaTarea2 BLOCKED
521.342 Wächter von LaTarea2 TIMED_WAITING
521.873 Wächter von LaTarea2 RUNNABLE
522.871 Wächter von LaTarea2 TIMED_WAITING
523.542 Wächter von LaTarea2 RUNNABLE
524.322 Wächter von LaTarea2 TIMED_WAITING
525.211 Wächter von LaTarea2 RUNNABLE
525.367 Wächter von LaTarea2 TIMED_WAITING
525.71 Wächter von LaTarea2 RUNNABLE
526.069 Wächter von LaTarea2 TIMED_WAITING
526.677 Wächter von LaTarea2 RUNNABLE
527.395 Wächter von LaTarea2 TERMINATED
527.489 LaTarea3 10952 Runde=10
515.399 Wächter von LaTarea3 NEW
515.867 Wächter von LaTarea3 RUNNABLE
517.13 Wächter von LaTarea3 TIMED_WAITING
517.598 Wächter von LaTarea3 RUNNABLE
517.879 Wächter von LaTarea3 TIMED_WAITING
518.425 Wächter von LaTarea3 RUNNABLE
518.597 Wächter von LaTarea3 TIMED_WAITING
519.345 Wächter von LaTarea3 RUNNABLE
519.86 Wächter von LaTarea3 BLOCKED
520.406 Wächter von LaTarea3 RUNNABLE
520.937 Wächter von LaTarea3 TIMED_WAITING
521.763 Wächter von LaTarea3 RUNNABLE
522.029 Wächter von LaTarea3 TIMED_WAITING
522.528 Wächter von LaTarea3 RUNNABLE
522.777 Wächter von LaTarea3 TIMED_WAITING
523.214 Wächter von LaTarea3 RUNNABLE
524.057 Wächter von LaTarea3 TIMED_WAITING
524.618 Wächter von LaTarea3 RUNNABLE
525.055 Wächter von LaTarea3 TIMED_WAITING
525.507 Wächter von LaTarea3 RUNNABLE
525.726 Wächter von LaTarea3 TIMED_WAITING
526.131 Wächter von LaTarea3 RUNNABLE
526.225 Wächter von LaTarea3 TIMED_WAITING
526.553 Wächter von LaTarea3 RUNNABLE
527.489 Wächter von LaTarea3 TERMINATED
527.598 LaTarea4 11404 Runde=9
528.097 LaTarea4 11903 Runde=10
515.445 Wächter von LaTarea4 NEW
515.929 Wächter von LaTarea4 RUNNABLE
516.303 Wächter von LaTarea4 TIMED_WAITING
517.037 Wächter von LaTarea4 RUNNABLE
517.926 Wächter von LaTarea4 TIMED_WAITING
518.425 Wächter von LaTarea4 RUNNABLE
518.846 Wächter von LaTarea4 TIMED_WAITING
519.345 Wächter von LaTarea4 RUNNABLE
520.235 Wächter von LaTarea4 TIMED_WAITING
521.015 Wächter von LaTarea4 RUNNABLE
521.841 Wächter von LaTarea4 TIMED_WAITING
522.185 Wächter von LaTarea4 RUNNABLE
522.84 Wächter von LaTarea4 TIMED_WAITING
523.417 Wächter von LaTarea4 RUNNABLE
524.4 Wächter von LaTarea4 TIMED_WAITING
525.414 Wächter von LaTarea4 RUNNABLE
525.617 Wächter von LaTarea4 TIMED_WAITING
526.194 Wächter von LaTarea4 RUNNABLE
526.49 Wächter von LaTarea4 TIMED_WAITING
527.411 Wächter von LaTarea4 RUNNABLE
527.598 Wächter von LaTarea4 TIMED_WAITING
527.91 Wächter von LaTarea4 RUNNABLE
528.097 Wächter von LaTarea4 TERMINATED
BUILD SUCCESSFUL (total time: 12 seconds)
Wie man sieht, bei jeder Runde geben die LaTarea-Threads eine Meldung aus; die Reihenfolge ist beliebig. Jedes mal wenn ein LaTarea-Thread seine 10 Durchläufen fertig hat, gibt sein Überwacher sein log aus. Am Anfang ist es immer NEW, dann meistens TIME_WAITING oder RUNNABLE und zum Schluß TERMINATED. Andere LaTarea-Threads die ihre Druchläufen noch nicht fertig haben folgen nach.
Und jetzt endlich mal die Fragen:
Zwischendurch erscheint mal ein BLOCKED, aber sehr selten. Bei insgesamt über 8 parallel laufende Threads hätte ich erwartet, daß diese Meldung viel öfter kommt (über 20 Versuche). Naja, eigentlich habe ich den Zustand WAITING erwartet, wenn gerade ein anderer Thread ausgeführt wird. Ist das normal und wie interpretiert ihr das?
Ich habe gemessen, wie lange es zwischen den Durchläufen der while-Schleife der Überwachungsmethode dauert. Da kam schon ein paar mal über eine Sekunde vor. Das ist extrem lang, wenn ich sofort über den Zustand von meinem Thread wissen will. Eine Erhöhung der Priorität hat da kein Besserung gebracht. Wie kann ich erzwingen, daß die while-Schleife exakt alle 1 msec durchgelaufen wird?
Wie kann man so eine Überwachung besser machen?
Mit welchem Tool tut man parallel laufende Threads am besten debuggen?
Wenn ich in netbeans einen breakpoint in den run()-Methoden setze, wird da alles gestoppt, auch die andere run()-Methode. Eventuell will ich aber, daß die weiterläuft. Irgendwann habe ich das beobachtet, kann es aber nicht mehr hinkriegen. Wie macht man das?