2011-01-25 24 views
1

私は、このようなコードを使用していないと言う本を読んでいます:スレッドの停止と同期

private volatile Thread myThread; 

.... 

myThread.stop(); 

代わりに、一つは使用する必要があります。残念ながら、被写体がどのさらに詳しく説明されていない

if (myThread != null) { 

Thread dummy = myThread; 

myThread = null; 

dummy.interrupt(); 


} 

を。誰かが私にこれを説明することができますか?

答えて

1

誰もがThread.stop()を呼び出さない理由について素晴らしい情報を与えてくれました。

セルゲイのコメントは、私がinterrupt()処理について与えた誤った情報を修正しました。私はlewapの答えのようにシグナルフラグを使うのが好きです。 Sergeyの言っているように、interrupt()はブロックされた操作のスレッドを起動させるためのものです。スレッドがブロッキング操作を呼び出さない場合、interrupt()はスレッドを実際に終了しません。あなたのスレッドは割り込みが呼び出されたかどうかを見るためにisInterrupted()を呼び出すことができます(シグナルフラグ、基本的に)。

あなたの本の例に戻って、私はそれが好きではありません。

if (myThread != null) { 

    Thread dummy = myThread; 

    myThread = null; 

    dummy.interrupt(); 

} 

この例では、ダミー変数にコピーする理由はありません。あなたは混乱するのが正しいです。

本書の著者は、他のスレッドが同時に同じスレッドを中断しようとは考えていないかもしれませんが、その割り込みコードはスレッドセーフではありません(「nullの場合にチェックしてヌルに設定」操作はアトミックではありません)。ダミーの割り当てを書くことは、実際のスレッドの安全性を追加することなく水を混乱させることです。

+1

スレッドの中断は必ずしも例外を生成しません。固定された一連のブロッキング操作のみが行われるため、どこにでも例外がスローされる可能性はありません。ブーリアンフラグと割り込みは、実際には何かを積極的に行っているスレッドに信号を送るためのものです。もう1つは、どこかでブロックされたスレッドを起動させることです(起動後ブールフラグをチェックできます)。また、InterruptedExceptionはチェックされた例外ですので、誤って処理することを忘れることはかなりありません。 –

+0

ああ、私の間違い。ありがとう、私は私の記事を修正しました。 – Astral

+1

投稿されたコード**は正しくありません**! 「スレッドダミー= myThread; if(dummy!= null){this.myThread = null; dummy.interrupt();} 'これまでのところ、最も古典的なデータ競合条件の中で最もクラスの高いものがあります。 – bestsss

3

stop()の方法hereを使用しない理由については、素晴らしい答えがあります。代わりに、あなたは無限にこの変数を使用してブール変数とループを保持することができ、この方法を使用する:

public class MyRunnable extends Runnable { 
    public volatile boolean keepRunning = true; 
    public void run() { 
     while (keepRunning) { 
      ... // do what you have to do 
     } 
    } 
} 

作業が終了することを決定したら、あなただけfalseにkeepRunning変数を設定する必要があります。あなたのスレッドは、次になります: - 残りの手順 を終える - あなたの仕事は、制御された方法で終了し、危険なstop()メソッドを使用していないような

を終了します。

+4

keepRunningはvolatileと宣言する必要があります。 –

+0

volatileキーワードのアドバイスをありがとう! – paweloque

3

stop()は推奨されていません。決して決して使用しないでくださいstop()。代わりにjava concurrencyを使用できます。

Javadocから:

この方法は、本質的に安全です。 Thread.stopを使用してスレッドを停止すると、ロックされたすべてのモニターのロックが解除されます(チェックされていないThreadDeath例外が当然スタックに伝播するため)。以前にこれらのモニターによって保護されたオブジェクトのいずれかが不整合な状態にあった場合、破損したオブジェクトは他のスレッドから見えるようになり、潜在的に任意の動作を引き起こします。多くの停止の使用は、ターゲットスレッドが実行を停止すべきであることを示すために単に変数を変更するコードに置き換えてください。ターゲットスレッドはこの変数を定期的にチェックし、変数が実行を停止することを示す場合はrunメソッドから順番に戻ります。ターゲットスレッドが(条件変数などで)長時間待機する場合は、割り込みメソッドを使用して待機を中断する必要があります。

Java Concurrency in Practice章7(キャンセルポリシーとシャットダウン)を見てください

+0

ええ、なぜそれを直接中断するのではなく、コピーして中断するのですか? – Mascarpone

+0

私は、同期のような他の問題に依存するかもしれない全体のコードを知りません。それに対処しなくてもinterrupt.interrupt()とnullを設定できる良い名前のダミーを持っています。 –

+1

b/c "非推奨"です。私は、コード化されていないサードパーティ製のライブラリを停止する必要がある場合があります(たとえば)。私はそれが実行コードを完全に制御できる場所では使用されないと同意しますが、私は*決して*一部では同意しません。 – bestsss

1

はThread.stopが廃止され、(詳細here)使用すべきではありません。

このコード例は、「myThread」への参照を無効にして、割り込みを通知しています。 "myThread!"がスレッドの唯一の参照であり、スレッド内で実行されているコードが割り込み要求を適切に処理している(無視していない)と仮定すると、スレッドは終了し、 "if(myThread!= null) "コードブロックは完了する。

+0

ええ、なぜそれを直接中断するのではなくコピーして中断するのですか? – Mascarpone

+0

多分、 "myThread"割り込みを呼び出すのを防ぐためです。そのメソッドへの別の呼び出しでは、myThreadがnullであり、コードブロックを再度実行しようとしていないことが検出されます。同期は処理する必要がありますが、私はそれが完全ではなく単純な例であると考えていました。 –

1

Thread.stopは廃止されましたが、また、Thread.stopを使用すると、コプレーマチェックの例外制御を回避することができます。たとえば、

public void doSomething(){ 
    Thread.currentThread().stop(new IOException()); 
} 

これはIOExceptionをスローします。IOExceptionは、チェックされたチェック例外です。コンパイラは、通常、クライアントに強制的にキャッチさせたり、メソッドにスローさせたりします。ここでdoSomethingがチェックされていないIOExceptionをスローする

+0

検証者は、チェックされた例外を主張しません。また、コードを動作させるには、 "stopThread"パーミッションが必要です。 – bestsss

+0

チェックされた例外を主張するのはどういう意味ですか?標準的なホットスポットのVMでは、私はこのコード行を簡単に実行できました。パーミッションはデフォルトで提供されているようです。 –

+0

もちろん、できます:)。サンドボックス(アプレット、Web-Startなど)で実行されていないjava ...は完全な権限を与えます。 'insisting'に関しては、チェックはコンパイラの一部であり、実際の実行時(検証者)はチェック例外とチェックされない例外をチェックしません。 – bestsss

1

@Paweloqueは、(完璧な方法である)を示唆したものに加えて、ストップを使用する別の代替が(ありが)here

を示唆した間違った方法:

アプレットが含まれているとし以下の開始、停止および実行方法:

private Thread blinker; 

public void start() { 
    blinker = new Thread(this); 
    blinker.start(); 
} 

public void stop() { 
    blinker.stop(); // UNSAFE! 
} 

public void run() { 
    Thread thisThread = Thread.currentThread(); 
    while (true) { 
     try { 
      thisThread.sleep(interval); 
     } catch (InterruptedException e){ 
     } 
     repaint(); 
    } 
} 

正しい方法

アプレットのstopおよびrunメソッドを次のように置き換えて、Thread.stopを使用することを避けることができます。 private volatile Thread blinker;

public void stop() { 
    blinker = null; 
} 

public void run() { 
    Thread thisThread = Thread.currentThread(); 
    while (blinker == thisThread) { 
     try { 
      thisThread.sleep(interval); 
     } catch (InterruptedException e){ 
     } 
     repaint(); 
    } 
} 
関連する問題