stopメソッドを使用してスレッドを停止せず、スレッドを停止する最善の方法
5475 ワード
スレッドの起動が完了すると、実行時に終了する必要がある場合があります.Javaが提供する終了方法はstopが1つしかありませんが、次の3つの問題があるため、この方法はお勧めしません.
(1) stopメソッドは時代遅れです
Java符号化ルールから言えば、もう古い方法は推奨されません.
(2) stopメソッドはコードロジックが不完全になる
stopメソッドは、stopメソッドが実行されると、スレッドロジックが完全であるかどうかにかかわらず、現在実行中のスレッドを終了する「悪意のある」割り込みです.次のコードを参照してください.
このコードの論理は、サブスレッドは匿名の内部クラスであり、runメソッドは実行時に1秒スリープした後、後続の論理を実行するが、メインスレッドはスリープ0.1秒後にサブスレッドの実行を終了する.すなわち、JVMはthread.stop()を実行すると、サブスレッドはsleep(1000)を実行し、stopメソッドはスタック内の情報を消去し、スレッドを終了する.これによりrunメソッドの論理が不完全になり、出力文printlnは論理を表し、サブスレッドのプライマリロジック、リソース回収、シナリオ初期化など、非常に重要である可能性がありますが、stopスレッドのため、これらは実行されなくなり、ビジネスロジックが不完全になる場合があります.
サブスレッドがいつ終了するか分からないため、Stopは基本的な論理整合性さえ保証できません.また、この操作も非常に隠蔽されており、サブスレッドがどこまで実行されるかは閉じられにくく、今後のメンテナンスに多くのトラブルをもたらします.
(3) stop法は原子論理を破壊する
マルチスレッドは共有リソースのプリエンプトの問題を解決するためにロック概念を使用し、リソースの同期を回避したが、そのためstop法はより大きなトラブルをもたらす:それはすべてのロックを廃棄し、原子論理が損なわれる.たとえば、次のようなプログラムがあります.
MultiThreadはRunnableインタフェースを実現し、マルチスレッド能力を備えている.runメソッドにsynchronizedコードブロックを加え、内部が原子論理であることを示している.それはまず自増してから自減する.synchronized同期コードブロックのルールに従って処理する.このとき、複数のスレッドを起動しても、印刷された結果はa=0であるべきである.しかし、実行中のスレッドがstopされると、この原子論理が破壊され、コードは次のようになります.
まず、すべてのスレッドが1つのSafeStopThreadのインスタンス変数tを共有していることを説明し、次にrunメソッドに同期コードブロックが追加されているため、synchronizedブロックに入るスレッドは1つしかない.このセグメントコードの
次の手順に従います.
1) スレッドtlが起動しrunメソッドが実行され、他のスレッドが同期コードブロックのロックを持っていないため、tlスレッドが加算後にsleepメソッドに実行されるとスリープが開始され、このときa=lとなる.
2) JVMはまた5つのスレッドを起動し、runメソッドも同時に実行し、synchronizedキーワードのブロック作用のため、この5つのスレッドは自己増加と自己減少操作を実行できず、tlスレッドロックの解放を待つ.
3) メインスレッドはtl.stopメソッドを実行し,tlスレッドを終了したが,a変数はすべてのスレッドで共有されるため,他の5つのスレッドで得られるa変数も1であることに注意した.
4) 他の5スレッドは、CPU実行機会を順次取得し、a値を印刷する.
こんなにたくさん分析して、読者も出力の結果を理解したと信じて、結果は以下の通りです.
Thread-5:a =1 Thread-4:a =1 Thread-3:a =1 Thread-2:a=1 Thread-1:a =1
synchronized同期コードブロックにおける論理はいずれも原子論理であり,外部スレッドの干渉を受けないことが期待されていたが,結果として原子論理が破壊される場合があり,stop法が廃棄される重要な原因の一つである原子論理が破壊される.
スレッドを終了してstopメソッドを使用できない以上、実行中のスレッドを終了するにはどうすればいいですか?答えも簡単で、カスタムフラグビットを使用してスレッドの実行状況を決定します.コードは以下の通りです.
このコードを実行すると、Runningが出力され、永遠に停止しないことがわかります.interruptを実行しても何の変化もないようです.それは、interruptメソッドがスレッド状態を終了することができず、中断フラグビット(tl.intemipt()の前後でtl.islntemipted()を出力する場合)だけを変更するためです.falseとtrueがそれぞれ出力されていることがわかります)、スレッドを終了する必要がある場合は、interruptを使用してより簡潔で安全な終了スレッドコードを記述するなど、自分で判断する必要があります.
つまり、実行中のスレッドを終了することが望ましい場合は、古いStopメソッドを使用することはできません.独自の符号化実装が必要です.これにより、原子論理が破壊されず、コード論理に異常が発生しないことを保証できます.もちろん、スレッドプール(ThreadPoolExecutorクラスなど)を使用している場合は、では、shutdownメソッドによってプール内のスレッドを徐々に閉じることができます.これは比較的穏やかで安全なスレッドを閉じるメソッドを採用しており、stopメソッドのような弊害は全く発生しません.
(1) stopメソッドは時代遅れです
Java符号化ルールから言えば、もう古い方法は推奨されません.
(2) stopメソッドはコードロジックが不完全になる
stopメソッドは、stopメソッドが実行されると、スレッドロジックが完全であるかどうかにかかわらず、現在実行中のスレッドを終了する「悪意のある」割り込みです.次のコードを参照してください.
public static void main(String[] args) throws Exception {
//
Thread thread = new Thread() {
@Override
public void run () {
try {
// 1 Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
System.out.printIn (" ");
}
};
// 、
thread.start();
// 0.1
Thread.sleep(100);
//
thread.stop();
}
このコードの論理は、サブスレッドは匿名の内部クラスであり、runメソッドは実行時に1秒スリープした後、後続の論理を実行するが、メインスレッドはスリープ0.1秒後にサブスレッドの実行を終了する.すなわち、JVMはthread.stop()を実行すると、サブスレッドはsleep(1000)を実行し、stopメソッドはスタック内の情報を消去し、スレッドを終了する.これによりrunメソッドの論理が不完全になり、出力文printlnは論理を表し、サブスレッドのプライマリロジック、リソース回収、シナリオ初期化など、非常に重要である可能性がありますが、stopスレッドのため、これらは実行されなくなり、ビジネスロジックが不完全になる場合があります.
サブスレッドがいつ終了するか分からないため、Stopは基本的な論理整合性さえ保証できません.また、この操作も非常に隠蔽されており、サブスレッドがどこまで実行されるかは閉じられにくく、今後のメンテナンスに多くのトラブルをもたらします.
(3) stop法は原子論理を破壊する
マルチスレッドは共有リソースのプリエンプトの問題を解決するためにロック概念を使用し、リソースの同期を回避したが、そのためstop法はより大きなトラブルをもたらす:それはすべてのロックを廃棄し、原子論理が損なわれる.たとえば、次のようなプログラムがあります.
public class SafeStopThread implements Runnable{
int a=0;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized ("") {
a++;
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
a--;
String tn=Thread.currentThread().getName();
System.out.println(tn+":a="+a);
}
}
}
MultiThreadはRunnableインタフェースを実現し、マルチスレッド能力を備えている.runメソッドにsynchronizedコードブロックを加え、内部が原子論理であることを示している.それはまず自増してから自減する.synchronized同期コードブロックのルールに従って処理する.このとき、複数のスレッドを起動しても、印刷された結果はa=0であるべきである.しかし、実行中のスレッドがstopされると、この原子論理が破壊され、コードは次のようになります.
public static void main(String[] args) {
SafeStopThread t=new SafeStopThread();
Thread t1=new Thread(t);
t1.start();
for(int i=0;i<5;i++){
/* SafeStopThread s=new SafeStopThread();
new Thread(s).start();*/ // stop
new Thread(t).start();//stop
}
t1.stop();//a==1
}
まず、すべてのスレッドが1つのSafeStopThreadのインスタンス変数tを共有していることを説明し、次にrunメソッドに同期コードブロックが追加されているため、synchronizedブロックに入るスレッドは1つしかない.このセグメントコードの
次の手順に従います.
1) スレッドtlが起動しrunメソッドが実行され、他のスレッドが同期コードブロックのロックを持っていないため、tlスレッドが加算後にsleepメソッドに実行されるとスリープが開始され、このときa=lとなる.
2) JVMはまた5つのスレッドを起動し、runメソッドも同時に実行し、synchronizedキーワードのブロック作用のため、この5つのスレッドは自己増加と自己減少操作を実行できず、tlスレッドロックの解放を待つ.
3) メインスレッドはtl.stopメソッドを実行し,tlスレッドを終了したが,a変数はすべてのスレッドで共有されるため,他の5つのスレッドで得られるa変数も1であることに注意した.
4) 他の5スレッドは、CPU実行機会を順次取得し、a値を印刷する.
こんなにたくさん分析して、読者も出力の結果を理解したと信じて、結果は以下の通りです.
Thread-5:a =1 Thread-4:a =1 Thread-3:a =1 Thread-2:a=1 Thread-1:a =1
synchronized同期コードブロックにおける論理はいずれも原子論理であり,外部スレッドの干渉を受けないことが期待されていたが,結果として原子論理が破壊される場合があり,stop法が廃棄される重要な原因の一つである原子論理が破壊される.
スレッドを終了してstopメソッドを使用できない以上、実行中のスレッドを終了するにはどうすればいいですか?答えも簡単で、カスタムフラグビットを使用してスレッドの実行状況を決定します.コードは以下の通りです.
public class SafeStopThread implements Runnable{
private volatile boolean stop=false;// volatile
int a=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(!stop){
synchronized ("") {
a++;
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
a--;
String tn=Thread.currentThread().getName();
System.out.println(tn+":a="+a);
}
}
//
public void terminate(){
stop=true;
}
public static void main(String[] args) {
SafeStopThread t=new SafeStopThread();
Thread t1=new Thread(t);
t1.start();
for(int i=0;i<5;i++){
new Thread(t).start();
}
t.terminate();
}
}
这是很简单的办法,在线程体中判断是否需要停止运行,即可保证线程体的逻辑完整性,而且也不会破坏原子逻辑。可能有读者对Java API比较熟悉,于是提出疑问:Thread不 是还提供了 interrupt中断线程的方法吗?这个方法可不是过时方法,那可以使用吗?它可以 终止一个线程吗?
非常好的问题,interrupt,名字看上去很像是终止一个线程的方法,但是我可以很明确 地告诉你,它不是,它不能终止一个正在执行着的线程,它只是修改中断标志而已,例如下面一段代码:
public static void main(String[]args) {
Thread tl - new Thread(){
public void run() {
// while (true) {
System, out .printIn ( "Running... ");
}
};
// tl
tl.start();
// tl
tl.interrupt 0;
}
このコードを実行すると、Runningが出力され、永遠に停止しないことがわかります.interruptを実行しても何の変化もないようです.それは、interruptメソッドがスレッド状態を終了することができず、中断フラグビット(tl.intemipt()の前後でtl.islntemipted()を出力する場合)だけを変更するためです.falseとtrueがそれぞれ出力されていることがわかります)、スレッドを終了する必要がある場合は、interruptを使用してより簡潔で安全な終了スレッドコードを記述するなど、自分で判断する必要があります.
class SafeStopThread extends Thread{
@Override
public void run() {
//
while(!islnterrupted()) {
II Do Something
}
}
}
つまり、実行中のスレッドを終了することが望ましい場合は、古いStopメソッドを使用することはできません.独自の符号化実装が必要です.これにより、原子論理が破壊されず、コード論理に異常が発生しないことを保証できます.もちろん、スレッドプール(ThreadPoolExecutorクラスなど)を使用している場合は、では、shutdownメソッドによってプール内のスレッドを徐々に閉じることができます.これは比較的穏やかで安全なスレッドを閉じるメソッドを採用しており、stopメソッドのような弊害は全く発生しません.