2010-09-19 24 views
5

Ich bin auf dem folgenden verwirrt:
Um Threads in einem Java-Programm zu verwenden, ist die einfachste Möglichkeit, Thread-Klasse zu erweitern und implementieren Sie die ausführbare Schnittstelle (oder einfach Runnable implementieren).
Um die Ausführung des Threads zu starten. Wir müssen die Methode start() des Threads aufrufen, die wiederum die Methode run() des Threads aufruft. Und so beginnt der Thread.
Die Methode start() (es sei denn, ich liege falsch) muss genau und nur einmal für jeden Thread aufgerufen werden. Daher können Thread-Instanzen nicht erneut verwendet werden, es sei denn, die run-Methode selbst läuft in einer Endlosschleife, die eine benutzerdefinierte Implementierung der Wiederverwendung des Threads erleichtert.
Nun ist die javadoc link text sagtJava-Thread-Wiederverwendung über Executor

Anrufe werden zuvor konstruierten Threads auszuführen wiederverwenden, wenn verfügbar

Ich verstehe nicht, wie dies umgesetzt wird. Ich biete in der Execute-Methode der Executor-Methode meinen benutzerdefinierten Thread z.

ExecutorService myCachedPool = Executors.newCachedThreadPool(); 
    myCachedPool.execute(new Runnable(){public void run(){ 
    //do something time consuming 

    }}); 

Wie kann dieser benutzerdefinierte Thread, den ich an das Executor-Framework delegiere, wiederverwendet werden?
Ist Executor erlaubt, Methode start() mehr als 1 Mal aufzurufen, während wir in unseren Programmen nicht können? Habe ich etwas falsch verstanden?

Vielen Dank.

Antwort

4

Beachten Sie, dass es nicht Executor ist, dass start() ruft - es ist ExecutorService. Und nein, es ruft nicht zweimal start() an. Es startet nicht die Aufgabe, die Sie es direkt mit Thread.start() geben ... stattdessen startet es einen Thread, der über die Arbeitswarteschlange dieses Threadpools informiert. Der Thread wird im Grunde warten, bis etwas Arbeit zu tun ist, dann wird er abgeholt und ausgeführt, bevor er zum Warten zurückkehrt. Obwohl der Thread mehrere Aufgaben ausführt, wird Thread.start() nur einmal aufgerufen.

EDIT: Nach den Kommentaren zu urteilen, sind Sie ein wenig verwirrt über den Unterschied zwischen einer Runnable (die eine Aufgabe ausgeführt wird) und Thread (was Aufgaben ausführt).

Derselbe Thread kann mehrere Aufgaben ausführen. Für ein sehr einfaches Beispiel dies kein Thread-Pool verwenden, sollten Sie:

(Ignorieren der möglichen Fadensicherheitsfragen eines List<T> von mehreren Threads verwenden.)

Sie könnten eine ganze Reihe von Runnable Aufgaben erstellen in der Lage, verschiedene Dinge zu tun, dann erstellen Sie eine einzige MultiRunnable, um sie wiederum zu betreiben. Übergeben Sie die Instanz von MultiRunnable in den Konstruktor Thread. Wenn Sie den Thread dann starten, wird jede der ursprünglichen ausführbaren Aufgaben ausgeführt. Hilft das?

+0

@ Jon: Sorry, ich dich verloren. Also werden die internen Threads des Frameworks wiederverwendet und nicht das ausführbare Runnable als Argument zur Ausführung? Mein Thread, den ich an das Framework delegiere, wird jedes Mal neu instanziiert, aber von der gleichen Instanz des internen Threads, der vom Framework erstellt wird? – Cratylus

+0

@ user384706: Ja. Ihr lauffähiges * ist kein * Thread - es ist nur eine auszuführende Aufgabe. Sie müssen zwischen den beiden unterscheiden; Sie sind sehr verschieden. –

+0

@Jon: Vielen Dank. Das einzige, was ich nicht sicher bin, ist, was ist der Vorteil der Verwendung der Executors.newCachedThreadPool(); Wenn meine Klasse, die Runnable (für eine Aufgabe) implementiert, teuer instanziiert wird, wird sie nicht wiederverwendet und derselbe Thread des Frameworks verwendet weiterhin neue Instanzen der Aufgabe. Was würde ich von dieser API gewinnen? Es sei denn, das Konzept besagt, dass jede Klasse, die Runnable implementiert, minimal ist. – Cratylus

5

Er ruft start() nicht mehr als einmal auf; Stattdessen wird der Thread im Pool nie abgeschlossen, sondern bleibt nur am Leben - Warten. Der Quellcode steht zum Herunterladen zur Verfügung, wenn Sie ihn ansehen möchten.

Jeder Thread in der Thread-Pool kann einfach wait() für den Executor, um es eine neue ausführbare Running, aber die eigene run() Methode Thread ist nicht abgeschlossen. Es wartet einfach auf ein neues Runnable, das dem Executor übergeben werden kann.

+0

Also meinst du, dass im Javadoc, wo es heißt, "dass zuvor konstruierte Threads wiederverwendet werden", es sich nicht auf das runnable bezieht, das ich an execute weiterleite, sondern an interne Threads des Executors-Frameworks? Also wird mein Runnable durch den gleichen Thread des Thread-Pools erneut instanziiert? Habe ich verstanden, was du sagst? – Cratylus

+2

Ihr Runnable wird nicht wiederhergestellt. Ihre Runnable-Instanz wird einem der Threads im Pool zugewiesen. Dieser Thread hat seine eigene Methode 'run()', die nicht durch die Methode run() 'von Runnable ersetzt werden kann (kann). Die run() -Methode des Threads ruft die 'run()' -Methode von 'Runnable' auf, und nachdem Ihre' Runnable.run() 'beendet ist, wird der Thread schließlich (es gibt eine Buchführung, die erledigt werden müsste) gehen zurück zu 'warten'. – jbindel

1

Um einen Thread mehr als einmal zu "starten", erstellen Sie einen Runnable. Zum Beispiel:

//NO 
private class T extends Thread { //not necessary to implement runnable 
    public void run(){ 
     //... 
    } 
} 
void someMethod(){ 
    T a = new T(); 
    a.start(); 
    a.start(); //NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO 
} 

Stattdessen

//Yes 
private class T implements Runnable { 
    public void run(){ 
     //... 
    } 
} 
void someMethod(){ 
    T a = new T(); 
    new Thread(a).start(); 
    new Thread(a).start(); //YES YES YES 
} 

Es ist auch möglich, dies zu tun:

void someMethod(){ 
    final Runnable r = new Runnable(){ 
     public void run(){ 
      //... 
     } 
    }; 
    new Thread(r).start(); 
    new Thread(r).start(); 
} 
// r could also be a field of you class.