如何知道线程是否在Java中完成?

时间:2017-03-19 12:35:13

标签: java multithreading

处理Java项目,我想知道一个线程是否已完成所需的计算。

首次尝试:runnable中的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));
    }
}

这是EdgeGenerator类

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();
    }
}

一切都可以,但有一点,那就是将线程中对象的值返回给主线程。

我想关注的变量是done类中的EdgeGenerator

我在这里试过几种方法。

首先是您可以在上面的代码中看到的实现:在所有计算之后设置this.done,然后通过调用isDone()返回。{ 但是,在致电isDone()时,它始终会返回false

第二次尝试:done在runnable

的调用者中

然后我决定在名为KochManager的{​​{1}}中创建一个变量,创建一个setter leftDone并在setLeftDone()中调用它。这也总是重新虚假。

管理器:     公共类KochManager {         私人决赛leftDone;         ...

EdgeGenerator

EdgeGenerator:

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

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

正如您可能已经猜到的那样也不起作用,所以经过一些搜索之后,我决定使用另一个具有单个值的对象。

第三次尝试:创建将保存要设置的变量的类public class EdgeGenerator { ... @Override public synchronized void run() { ... switch (this.edgeLocation) { case LEFT: this.koch.generateLeftEdge(); this.kochManager.setLeftDone(true); break; ... } } }

管理器:

Done

EdgeGenerator:

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();
        }
        ...
    }
}

一旦这没有成功,我决定拨打StackOverflow的帮助。 有人可以帮助我吗?

3 个答案:

答案 0 :(得分:5)

  

然而,当调用isDone()时,它总是返回false

您需要使用选项-1,但将done变量标记为volatile,如下所示,否则其他线程将无法保证看到done的更改1}}变量

private volatile boolean done;

以下是here关于volatile

的引用
  

对volatile变量的更改始终对其他线程可见。   更重要的是,它还意味着当线程读取volatile时   变量,它不仅看到了对volatile的最新变化,而且还看到了变量   导致变化的代码的副作用。

答案 1 :(得分:1)

你的代码的问题在于你有一个常见的并发问题:内存可见性。当一个线程更新完成时,其他人不会看到它已更新。您必须将 done 变量声明为volatile,以防止此问题发生:

volatile boolean done;

答案 2 :(得分:0)

问题是缓存了done的值。您需要将其标记为volatile,以便从各个线程调用它始终获得最新值。