問題は、外部スレッドを持つことは可能ですか、それともそれらが実行されるクラスの内部にある必要があるかということです。(おねじ)
1 に答える
スレッド、またはより正確には、実行のスレッドは何かであり、クラスThread
は密接に関連しているが異なるものであり、これら 2 つの概念を混同しているようです。
実行スレッドは、操作を順次実行するマシンと考えることができます。このようなマシンを定義して実行する 1 つの方法MyClass
は、main()
メソッドと呼び出しを含むクラスを作成することjava MyClass
です。
もう 1 つの方法は、Thread
クラスの新しいインスタンスを作成し、そのメソッドを呼び出すことstart()
です。これにより、デフォルトでは何もしないクラスのメソッドにあるコードを実行する新しい実行スレッドが作成されます。これが役立つようにするには、通常、メソッドをオーバーライドします。これは、クラスの内部スレッドを呼び出していると思います... :run()
Thread
run
class MyThread extends Thread {
@Override public void run() {
// ... some code ...
}
}
// ...
final Thread t = new MyThread();
t.start();
この例でrun()
は、クラスのメソッドがMyThread
戻った後、そのインスタンスに関連付けられた実行スレッドMyThread
が終了します (シングルスレッド プログラムがメソッドから戻ったとき、またはmain()
メソッドの終わりに到達したときと同様)。
もう 1 つの可能性はThread
、 a のインスタンスを渡すことRunnable
です。次に、2 つの概念を分離します。のインスタンスで表される実行のスレッドはThread
、 のインスタンスでコードを実行しますRunnable
。
class MyRunnable implements Runnable {
@Override public void run {
// this code will get executed by a thread
}
}
// ...
final MyRunnable r = new MyRunnable();
final Thread t = new Thread(t);
t.start();
これは、外部スレッドと呼ぶものに近いかもしれませんが、この命名法は非常に型にはまらないものです。
したがって、ここには 2 つの異なるが密接に関連する概念があることがわかります。
さて、Java では、実行するコードを与えるのを待っている実行スレッドを作成する方法があります。作成された後、プールに移動し、そこに座っています。実行するコードを送信し、終了すると、終了するのではなく、実行のスレッドが存続し、そのプールに戻ります。多分これはあなたが探しているものです。
これを行うには、通常、ExecutorService
. 例えば:
class MyMainClass {
private static final ExecutorService es = Executors.newFixedThreadPool(10);
public static void main(String... args) {
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.submit(new MyRunnable());
}
}
この例では、プールには 10 個の実行スレッドが含まれています。任意の数のインスタンスを送信できRunnable
、10 個のスレッドに分散されます。を呼び出すたびsubmit(...)
に のExecutorService
インスタンスが返されますFuture
。これを使用して、実行中の実行スレッドがRunnable
既に終了したかどうか、正常に終了したか、キャッチされなかった例外が原因で終了したかを知ることができます。
Thread
ここで言及したすべてのクラス( 、Runnable
、ExecutorService
、Executors
および)の javadoc を確認することをお勧めしますFuture
。このドキュメントから学ぶことはたくさんあります。
ExecutorService
最後に、スレッドとs をいじり始めると、あらゆる種類の頭痛が発生することを覚えておいてください。実行が続行できない状況 (デッドロック、ライブロック)、アトミックである必要がある操作 (つまり、異なるスレッドからの変数のインクリメント)、メモリの可視性 (つまり、フィールドの値を変更した場合) について考える必要があります。 「注意」を怠ると、他のスレッドがそのフィールドの変更にまったく気付かない可能性があります!)。また、JVM はデーモン以外のスレッドが最後まで終了しないことにも注意してください。Runnable
つまり、上の例は、サブミットされたすべてのs が終了しても決して終了しません。これは、の実行スレッドExecutorService
がまだ生きているためです!