web-dev-qa-db-ja.com

コンストラクターでスレッドを開始しないのはなぜですか?終了する方法は?

Javaでスレッドを使用する方法を学んでいます。そして、Runnableを実装して別のスレッドと同時に実行するクラスを作成しました。メインスレッドはシリアルポートのリッスンを処理し、2番目のスレッドは同じポートへのデータ送信を処理します。

public class MyNewThread implements Runnable {
    Thread t;

    MyNewThread() {
        t = new Thread (this, "Data Thread");
        t.start();
    }

    public void run()  {
        // New Thread code here 
    }

最初のスレッドは次のように2番目のスレッドを開始します。

public class Main {
    public static void main(String[] args) throws Exception{
        new MyNewThread();
        // First thread code there
    }  
}

これは機能しますが、私のコンパイラーは、「コンストラクターで新しいスレッドを開始することは危険です」という警告にフラグを立てます。どうしてこれなの?

この質問の2番目の部分は、1つのスレッド(シリアルポートリスンスレッド)でループを実行し、2番目のスレッドでexitコマンドを入力する方法です。終了する最初のスレッドを取得するにはどうすればよいですか?ありがとう。

46
Zac

最初の質問:thisを渡すコンストラクタでスレッドを開始すると、thisがエスケープされます。つまり、オブジェクトが完全に構築される前に、実際にオブジェクトへの参照を提供しているということです。スレッドは、コンストラクターが終了する前に開始されます。これにより、あらゆる種類の奇妙な動作が発生する可能性があります。

2番目の質問:Javaで別のスレッドを強制的に停止する方法はないため、スレッドが停止するかどうかを確認するためにスレッドがチェックする変数を使用します。他のスレッドは、最初のスレッドが停止することを示すように設定します。適切な公開を保証するために、変数は揮発性であるか、すべてのアクセスが同期されている必要があります。ここにあなたが望むもののようなものになるいくつかのコードがあります。

public class MyNewThread implements Runnable {

    private final Thread t;
    private volatile boolean shouldStop = false;

    MyNewThread() {
        t = new Thread (this, "Data Thread");
    }

    public void start() {
        t.start();
    }

    public void stop() {   
         shouldStop = true;
    }

    public void run()  {
         while(!shouldStop)
         {
             // do stuff
         }
    }
}

スレッドを作成して開始したいものは何でもします:

MyNewThread thread = new MyNewThread();
thread.start();

スレッドを停止したいものは何でもします:

thread.stop();
45
Justin Waugh

基本的な例を見てみましょう。

class MyClass implements Runnable{
   int a = 0;
   String b = null;

   public MyClass(){
       new Thread(this).start();
       b = "Foo";
   }

   public void run(){
      a = b.length(); //can throw NullPointerException
   }
}

この場合、MyClass.thisは、コンストラクターをescapeと呼びます。つまり、オブジェクトは参照できますが、コンストラクターで構築されるすべてのフィールドが作成されない場合があります。これを別のレベルに移動するには、bがfinalだった場合、それが利用可能であると期待しますが、保証されません。これは部分的に構築されたオブジェクトとして知られており、Javaでは完全に合法です。

8
John Vint

2番目の質問については、isAliveメソッドによって2番目のスレッドが終了したかどうかを確認できます。yesの場合、breakキーワードを使用して最初のスレッドのループをオフにします。行う

public class MyNewThread implements Runnable {
Thread t;

MyNewThread() {
    t = new Thread (this, "Data Thread");
    t.start();
}

public void run()  {

   reading code ................
    // New Thread code here 
}

public class Main {
public static void main(String[] args) throws Exception{
   MyNewThread thread = new MyNewThread();

while(true)
{
    listening code ...................

    if(!thread.t.isAlive())
      break;
 }

}  
}
0
user1841718