2017-03-19 6 views
4

Javaプロジェクトで作業しており、スレッドが必要な計算を完了したかどうかを知りたいと思います。スレッドがJavaで終了したかどうかを知る方法?

は最初の試み:実行可能

done変数は、最初のクラスは、マネージャ

import uckochfractalfx.UCKochFractalFX; 

public class KochManager { 
    private final UCKochFractalFX application; 
    private final IEdgeCollection edges; 

    private int level; 
    private int count; 

    public KochManager(UCKochFractalFX application) { 
     this.application = application; 
     this.edges = new EdgeArrayList(); 
    } 

    public synchronized void changeLevel(int nxt) { 
     this.level = nxt; 
     this.count = 0; 
     this.edges.clear(); 

     EdgeGenerator left, right, bottom; 
     left = new EdgeGenerator(this, EdgeLocation.LEFT); 
     right = new EdgeGenerator(this, EdgeLocation.RIGHT); 
     bottom = new EdgeGenerator(this, EdgeLocation.BOTTOM); 

     Thread tLeft, tRight, tBottom; 
     tLeft = new Thread(left); 
     tRight = new Thread(right); 
     tBottom = new Thread(bottom); 

     tLeft.start(); 
     tRight.start(); 
     tBottom.start(); 

     while (!(left.isDone() && right.isDone() && bottom.isDone()) { 
       wait(); 
     } 

     this.application.setTextCalc(String.valueOf(this.totalTimeExecution)); 
     this.application.setTextNrEdges(String.valueOf(this.count));  
     application.requestDrawEdges(); 
    } 

    public synchronized void addEdge(Edge edge) { 
     this.edges.add(edge); 
    } 

    public synchronized void increaseCount() { 
     count++; 
    } 

    public int getLevel() { 
     return level; 
    } 

    public void drawEdges() { 
     this.application.clearKochPanel(); 
     this.edges.getAll().forEach((Edge e) -> this.application.drawEdge(e)); 

     this.application.setTextDraw(String.valueOf(this.totalTimeExecution)); 
    } 
} 

であり、これは

import java.util.Observable; 
import java.util.Observer; 

public class EdgeGenerator implements Runnable, Observer { 

    private final KochManager kochManager; 
    private final EdgeLocation edgeLocation; 
    private final KochFractal koch; 
    private boolean done; 

    public EdgeGenerator(KochManager kochManager, EdgeLocation edgeLocation) { 
     this.kochManager = kochManager; 
     this.edgeLocation = edgeLocation; 

     this.koch = new KochFractal(); 
     this.koch.addObserver(this); 
    } 

    @Override 
    public synchronized void run() { 
     koch.setLevel(kochManager.getLevel()); 
     this.done = false; 

     switch (this.edgeLocation) { 
      case LEFT: 
       this.koch.generateLeftEdge(); 
       break; 
      case RIGHT: 
       this.koch.generateRightEdge(); 
       break; 
      case BOTTOM: 
       this.koch.generateBottomEdge(); 
       break; 
     } 
     this.done = true; 
    } 

    public boolean isDone() { 
     return done; 
    } 

    @Override 
    public void update(Observable o, Object o1) { 
     this.kochManager.addEdge((Edge) o1); 
     this.kochManager.increaseCount(); 
    } 
} 

すべてはなく、一つのことを作品EdgeGeneratorクラスであり、それは、スレッド内のオブジェクトの値をメインスレッドに戻します。

ここでは、EdgeGeneratorクラスのdoneに焦点を当てたい変数を使用します。

私はここでいくつかの方法を試しました。

最初のコードは上記のコードで確認できます。isDone()を呼び出して返す必要があるすべての計算後にthis.doneを設定します。 isDone()を呼び出すとき
しかし、それは常にfalse

第二の試みを返します。

実行可能

の呼び出し元で doneそれから私は、 leftDoneと呼ばれる KochManagerで変数を作成セッター setLeftDone()を作成し、 EdgeGeneratorでそれを呼び出すことにしました。これはまた常に偽を返します。

マネージャ: public class KochManager { private final leftDone; ...

public void setLeftDone(boolean done) { 
     this.leftDone = done; 
    } 
    ... 

    public synchronized void changeLevel(int nxt) { 
     ... 
     while (!(this.leftDone && this.rightDone && this.BottomDone)){ 
      wait(); 
     } 
     ... 
    } 
} 

EdgeGenerator:

public class EdgeGenerator { 
    ... 
    @Override 
    public synchronized void run() { 
     ... 
     switch (this.edgeLocation) { 
      case LEFT: 
       this.koch.generateLeftEdge(); 
       this.kochManager.setLeftDone(true); 
       break; 
      ... 
     } 
    } 
} 

ご想像のとおり、いくつかのより多く検索した後、私は単一の値を持つことになり、別のオブジェクトを使用することにしましたので、どちらか動作しませんでした。

第3の試み:設定する変数を保持するクラスDoneを作成します。

マネージャー:

public class KochManager { 
    private class Done { 
     public boolean done; 
    } 
    ... 

    private Done leftDone; 

    public KochManager(UCKochFractalFX application) { 
     this.application = application; 
     this.edges = new EdgeArrayList(); 
     this.leftDone = new Done(); 
    } 

    public void setLeftDone(boolean done) { 
     this.leftDone.done = done; 
    } 
    ... 

    public synchronized void changeLevel(int nxt) { 
     ... 
     while (!(this.leftDone.done && this.rightDone.done && this.BottomDone.done)){ 
      wait(); 
     } 
     ... 
    } 
} 

EdgeGenerator:これがうまくいかなかった後はどちらか、私はStackOverflowのの助けを呼ぶことにしました

public class EdgeGenerator { 
    ... 
    @Override 
    public synchronized void run() { 
     ... 
     switch (this.edgeLocation) { 
      case LEFT: 
       this.koch.generateLeftEdge(); 
       this.kochManager.setLeftDone(true); 
       break; 
      ... 
     } 
    } 
} 

。 誰かが私を助けてくれますか?

+4

あなたの最初のアプローチの問題は、 'done'は、揮発性(と' isDone(ではないということです) 'ではありません同期されているため)、コードはスレッドセーフではなく、古い 'false'値を取得している可能性があります。 – Kayaman

+4

これを処理するために 'Executor'を使って' Future'のようなものを使うことをお勧めします。 – Kayaman

+1

'wait()'の呼び出しが何を理解していますか?実際に 'notify()'を呼びますか? –

答えて

5

)(isDoneを呼び出すときしかし、それは常にそうでない場合は、他のスレッドはできませんあなたはオプション-1と一緒に行きますが、以下に示すようにvolatileとしてあなたdone変数をマーク、する必要が

偽を返します。 done変数
への変更を確認することが保証されています。

private volatile boolean done; 

次は、揮発性変数へhere程度volatile

変更から取られた引用であるが、常に他のスレッドに表示されます。 さらに、スレッドが揮発性の 変数を読み取ったときに、volatileの最新の変更だけでなく、 の変更の原因となったコードの副作用も認識します。

0

問題は、doneの値がキャッシュされていることです。さまざまなスレッドからの呼び出しが常に最新の値になるように、volatileとマークする必要があります。

1

コードの問題は、メモリの可視性の並行性を持つ一般的な問題点の1つを持つことです。あるスレッドがを完了すると、は更新されていません。あなたはが起きてからこの問題を回避するために揮発性として変数を行ってあなたを宣言する必要があります。

volatile boolean done; 
関連する問題