私は Java のスレッドに苦労しています。スレッド 1、スレッド 2、およびスレッド 3 の 3 つのスレッドがあります。これらは開始時に何らかのタスクを実行しているため、これらの 2 つのスレッドをスレッド 1 で停止したいと考えています。に thread1 を置きsleep(500)
、両方のスレッドを停止しましたが、2 つのスレッドのプロセスがまだ実行されています。これを行う方法はありますか?
3 に答える
どのように彼らを止めようとしていますか?Thread.stop
?このメソッドは非推奨であることに注意してください。
代わりに、スレッド1に何らかのフラグを使用して、スレッド2と3に停止するように通信することを検討してください。実際、おそらく割り込みを使用できます。
以下では、Thread.interruptを使用して調整を実装しています。
final Thread subject1 = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Thread.yield();
}
System.out.println("subject 1 stopped!");
}
});
final Thread subject2 = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Thread.yield();
}
System.out.println("subject 2 stopped!");
}
});
final Thread coordinator = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) { }
System.out.println("coordinator stopping!");
subject1.interrupt();
subject2.interrupt();
}
});
subject1.start();
subject2.start();
coordinator.start();
または、通信手段として
volatile boolean
(またはAtomicBoolean )を使用することもできます。によって提供されるアトミックアクセスにより、フラグの変更がサブジェクトスレッドによって確実に認識されるようになりますvolatile
。java.util.concurrent.atomic.*
final AtomicBoolean running = new AtomicBoolean(true);
final ExecutorService subjects = Executors.newFixedThreadPool(2);
subjects.submit(new Runnable() {
public void run() {
while (running.get()) {
Thread.yield();
}
System.out.println("subject 1 stopped!");
}
});
subjects.submit(new Runnable() {
public void run() {
while (running.get()) {
Thread.yield();
}
System.out.println("subject 2 stopped!");
}
});
final ScheduledExecutorService coordinator = Executors.newSingleThreadScheduledExecutor();
coordinator.schedule(new Runnable() {
public void run() {
System.out.println("coordinator stopping!");
running.set(false);
subjects.shutdown();
coordinator.shutdown();
}
}, 500, TimeUnit.MILLISECONDS);
AtomicBoolean
同様に、次のようなフィールドを使用するのではなく、使用することを選択できます。
static volatile boolean running = true;
さらに良いことに、ExecutorServiceを利用する場合は、次のように同様のコードをプログラムすることもできます。
final ExecutorService subjects = Executors.newFixedThreadPool(2);
subjects.submit(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Thread.yield();
}
System.out.println("subject 1 stopped!");
}
});
subjects.submit(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Thread.yield();
}
System.out.println("subject 2 stopped!");
}
});
final ScheduledExecutorService coordinator = Executors.newSingleThreadScheduledExecutor();
coordinator.schedule(new Runnable() {
public void run() {
System.out.println("coordinator stopping!");
subjects.shutdownNow();
coordinator.shutdown();
}
}, 500, TimeUnit.MILLISECONDS);
これは、 ThreadPoolExecutor.shutdownNowが、シャットダウンを通知するためにワーカースレッドに割り込むという事実を利用しています。
任意の例を実行すると、出力は次のような効果が得られるはずです。
C:\dev\scrap>javac CoordinationTest.java
C:\dev\scrap>java CoordinationTest
coordinator stopping!
subject 1 stopped!
subject 2 stopped!
最後の2行はどちらの順序でもかまいません。
別のスレッドからスレッドを停止することはできません。スレッドに自分自身を停止するように要求することしかできません。それを行う最善の方法は、スレッドを中断することです。ただし、中断されたスレッドは協力して、実行を停止することでできるだけ早く中断に応答する必要があります。
これについては、並行性に関する Java チュートリアルで説明されています。
次のいずれかを実行できます。
- スレッドが定期的にチェックするブールフラグをいくつか用意します。変更されると、実行が停止します (競合状態が発生する可能性があることに注意してください)。
- 別のオプションは、次を使用すること
ExecutorService
です。
終了を管理するメソッドと、1 つ以上の非同期タスクの進行状況を追跡するための Future を生成できるメソッドを提供する Executor。