确保java线程真正挂起

d8tt03nd  于 2021-07-03  发布在  Java
关注(0)|答案(3)|浏览(412)

我有以下课程:

public class PawnThread implements Runnable {

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

    @Override
    public void run() {
        try {
            while (... some finish condition ...) {
                move();
                synchronized (this) {
                    while (suspendFlag) {
                        wait();
                    }
                }
            }
        } catch (InterruptedException e) {
            System.err.println(pawn.toString() + ": thread interrupted :(");
        }
    }

    void move() {
        ... some blocking actions
    }

    synchronized void suspend() {
        suspendFlag = true;
    }

    synchronized void resume() {
        suspendFlag = false;
        notify();
    }
}

现在我有了它的对象列表: private final List<PawnThread> pawnThreadList; 我定义了一些helper方法来挂起它们:

public void suspendAll() {
   pawnThreadList.forEach(PawnThread::suspend);
}

现在 suspend() 方法只是关于更改标志。要求是,当我离开的时候 suspendAll() 方法时,所有线程都应实际暂停(它们不能处于 RUNNABLE 州政府)-现在不是这样,因为对他们中的一些人来说,可能需要一些时间才能真正完成暂停前的工作。
我将非常感谢您的建议,什么是正确的设计为这个解决方案。
当做

ippsafx7

ippsafx71#

这个要求不可能满足,但也毫无意义。为了让线程传递它已挂起的事实,线程必须正在运行。无法确保线程已完成挂起过程。
但这也不是一个明智的要求。线程是否已经挂起自己或者即将挂起自己,只要它除了挂起自己什么都不用做,这怎么可能有关系呢?
一个合理的需求应该通过让每个线程在某个地方设置一些指示来满足,即它已经接收到挂起请求并且即将停止执行。然后调用线程可以等待所有线程提供该指示。

j2qf4p5b

j2qf4p5b2#

制造 PawnThread#suspend() 等待暂停完成:

public class PawnThread implements Runnable {
    private final Waiter suspender = new Waiter();
    private final Waiter suspending = new Waiter();

    @Override
    public void run() {
        try {
            while (...) {
                suspending.suspend();
                move();
                suspending.resume();
                suspender.await();
            }
        } catch (InterruptedException e) {
            ...
        }
    }

    void suspend() throws InterruptedException {
        suspender.suspend();
        suspending.await();
    }

    void resume() {
        suspender.resume();
    }
}

public class Waiter {
    private boolean waiting;

    public synchronized void await() throws InterruptedException {
        while (waiting) {
            wait();
        }
    }

    public synchronized void suspend() {
        waiting = true;
    }

    public synchronized void resume() {
        waiting = false;
        notify();
    }
}
pftdvrlh

pftdvrlh3#

任何并行解决方案的通用正确设计都是定义令牌流和触发规则(参见petry net tedminology)。最简单和有用的触发规则是在所有输入标记就绪时启动操作。在您的情况下,输入标记隐藏在whle条件和suspend条件中。您的错误是您将suspend condition定义为负数,而所有标记都必须定义为正数。也就是说,线程在有足够的令牌的地方工作,当它们用完时停止,然后线程等待,同时外部线程增加令牌的数量。
令牌可以有两种-黑色(纯权限),通过信号量传递,以及颜色(消息),通过阻塞队列传递。这两个通信器类涵盖了大多数用例。在某些复杂的情况下,用户可以使用synchronized/wait/notify创建自定义的通信程序。
因此,设计任何并行程序的标准方法如下:
设计petry网,其中包含标记(通信者)和转换(动作)的位置。
将位置Map到信号量/阻塞队列/自定义通讯器,并转换到线程(或参与者)。

相关问题