简体   繁体   English

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

[英]How to know if a thread is finished in Java?

Working on a Java project and I would like to know if a thread has finished the required calculations. 在Java项目上工作,我想知道一个线程是否已完成所需的计算。

First attempt: done variable in runnable 第一次尝试:在runnable中done变量

The first class is a manager 第一堂课是经理

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

And this is the EdgeGenerator class 这是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();
    }
}

Everything works but one thing, and that is getting the values from the objects in the thread back to the main thread. 一切只有一件事,那就是将线程中对象的值返回到主线程。

The variable I would like to focus on here is done in the EdgeGenerator class. 我想在这里关注的变量是在EdgeGenerator类中done的。

I have tried a couple of ways here. 我在这里尝试了几种方法。

First is the implementation as you can see it in the code above: Set this.done after all the calculations, which should then be returned by calling isDone() . 首先是你可以在上面的代码中看到的实现:在所有计算之后设置this.done ,然后通过调用isDone()返回。
However when calling isDone() it always returns false 但是当调用isDone()它总是返回false

Second attempt: done in caller of runnable 第二次尝试:在runnable的调用者中done

Then I decided to create a variable in KochManager called leftDone , create a setter setLeftDone() and call that in EdgeGenerator . 然后我决定在KochManager创建一个名为leftDone的变量,创建一个setter setLeftDone()并在EdgeGenerator调用它。 This also always retuned false. 这也总是重新虚假。

Manager: public class KochManager { private final leftDone; 经理:公共课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: EdgeGenerator:

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

As you might have guessed that didn't work either, so after some more searching I decided to use another object that would have a single value. 正如您可能已经猜到的那样也不起作用,因此在进行了一些搜索之后我决定使用另一个具有单个值的对象。

Third attempt: Create class Done that would hold a variable to be set. 第三次尝试:创建将保存要设置的变量的类Done

Manager: 经理:

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: EdgeGenerator:

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

Once this did not work out either I decided to call the help of StackOverflow. 一旦这没有成功,我决定调用StackOverflow的帮助。 Can someone help me out here? 有人可以帮帮我吗?

However when calling isDone() it always returns false 但是当调用isDone()时,它总是返回false

You need to go with Option-1, but mark your done variable as volatile as shown below, otherwise the other threads will not be guaranteed to see the changes to the done variable . 你需要使用Option-1,但是将你的done变量标记为volatile ,如下所示, 否则其他线程将无法保证看到对done变量的更改

private volatile boolean done;

The following is the quote taken from here about volatile 以下是摘自该帖点击这里了解volatile

Changes to a volatile variable are always visible to other threads. 对volatile变量的更改始终对其他线程可见。 What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change. 更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用。

The problem with your code is that you have one of the common gotchas with concurrency: memory visibility. 你的代码的问题在于你有一个常见的并发问题:内存可见性。 When one thread updates done the others don't see it has been updated. 当一个线程更新完成时 ,其他线程不会看到它已更新。 You must declare you done variable as volatile in order to prevent this issue from happening: 您必须声明你为了防止这个问题的发生做了作为volatile变量:

volatile boolean done;

The problem is the value of done is cached. 问题是done的值是缓存的。 You need to mark it as volatile so that calls to it from various threads always get the most up-to-date value. 您需要将其标记为volatile以便从各个线程调用它始终获得最新值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM