java - 线程组调用中断后留下僵尸线程

标签 java multithreading synchronization interrupt

我有一个主管线程和一些工作线程。假设我们有 Sprite 包装礼物并将其发送到工厂,工厂将它们放入队列中。收到一定数量的礼物后,主管要求停止工作。

我的所有工作线程都属于一个线程组。当supervisor意识到已经达到了所需的礼物数量时,它会调用workersThreadGroup.interrupt()。然而,总有一个僵尸 worker 留下来继续生产。

现在,对于一些代码:

public class Factory implements Runnable {

    @Override
    public void run() {
        createElves();
        startElves();

        while (goalNotAchieved) {
            orchestrator.awaitSupervisorTurn();
            System.out.println("Factory " + factoryID + " is working..");
            orchestrator.setWorkersTurn();


        }


        System.out.println("Factory " + factoryID + " FINISHED");
        joinElves();

    }


    private void joinElves() {
        for (int i = 0; i < numberOfElves; i++) {
            try {
                elvesThreads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void startElves() {
        for (int i = 0; i < numberOfElves; i++) {
            elvesThreads[i].start();
        }
    }

    private void createElves() {
        for (int i = 0; i < numberOfElves; i++) {
            IPosition elfPosition = positionBuilder.create(matrixSize, elfMap);
            ElfRunnable elfRunnable = elfBuilder.create(i, this, elfPosition,
                                                        orchestrator);
            elfMap.addEntry(elfRunnable, elfPosition);
            elfPosition.setOwner(elfRunnable);
            elvesThreads[i] = new Thread(elvesThreadGroup, elfRunnable);
        }
    }

    private synchronized void queryPositions() {
        try {
            positionQuerySemaphore.acquire();
            System.out.println("Factory " + factoryID + " starting query....");
            for (ElfRunnable elf : elves) {
                System.out.println("Queried " + elf + ": (" + elf.getElfPosition());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            positionQuerySemaphore.release();
        }

    }


    public synchronized void notifyGiftCreated(Gift gift) {
        if (producedGifts == maxGifts) {
            elvesThreadGroup.interrupt();
            goalNotAchieved = false;
            orchestrator.setWorkersTurn();
            System.out.println("Rejecting " + gift);

        } else {
            producedGifts++;
            System.out.println("GIFTS: " + producedGifts);
        }


    }

}


public class ElfRunnable implements Runnable {

    @Override
    public void run() {
        notifySupervisorFactory();
        while (threadIsAlive()) {

            orchestrator.awaitWorkersTurn();
            if (elfPosition.randomMove()) {
                Gift gift = new Gift(random.nextInt(), ID);
                orchestrator.setSuperVisorTurn();
                supervisorFactory.notifyGiftCreated(gift);
                rest();
            } else {
                awaitRandom();
            }


        }
        System.out.println("Elf " + ID + "/" + supervisorFactory + " is DONE");
    }

    private boolean threadIsAlive() {
        return !Thread.currentThread().isInterrupted();
    }


    private void notifySupervisorFactory() {
        supervisorFactory.becomeAware(this);
    }

    private void rest() {
        try {
            Thread.sleep(30);
        } catch (InterruptedException ignored) {
        }

    }

    private void awaitRandom() {

        int minimum = 10;
        int maximum = 50;
        int waitingTime = random.nextInt(maximum - minimum) + minimum;
        try {
            Thread.sleep(waitingTime);
        } catch (InterruptedException ignored) {
        }
    }


}


public class Orchestrator implements IDefinitions {
    private volatile int turn;

    public Orchestrator(int turn) {
        this.turn = turn;
    }

    public synchronized void awaitWorkersTurn() {
        while (turn == supervisorTurn) {
            try {
                wait();
            } catch (InterruptedException ignored) {
                return;
            }
        }
    }

    public synchronized void awaitSupervisorTurn() {
        while (turn == workerTurn ) {
            try {
                wait();
            } catch (InterruptedException ignored) {
                return;
            }
        }

    }

    public synchronized void setWorkersTurn() {
        turn = workerTurn;
        notifyAll();
    }

    public synchronized void setSuperVisorTurn() {
        turn = supervisorTurn;
        notifyAll();
    }



}

现在,我在输出过程中得到什么:

Factory 0 got: 20 toys to produce, 347 as matrix size, 5 elves
Thread elf 0/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 1/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 2/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 3/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Thread elf 4/0 group: java.lang.ThreadGroup[name=main,maxpri=10]
Factory 0 is working..
Elf 1 created a gift
Elf 3 created a gift
Elf 0 created a gift
Elf 4 created a gift
Elf 2 created a gift
Factory 0 is working..
GIFTS: 1
GIFTS: 2
GIFTS: 3
GIFTS: 4
GIFTS: 5
Elf 4 created a gift
Elf 2 created a gift
Elf 3 created a gift
Factory 0 is working..
GIFTS: 6
Elf 1 created a gift
Elf 0 created a gift
Factory 0 is working..
GIFTS: 7
GIFTS: 8
GIFTS: 9
GIFTS: 10
Elf 2 created a gift
GIFTS: 11
Elf 0 created a gift
GIFTS: 12
Elf 4 created a gift
Elf 3 created a gift
Factory 0 is working..
Elf 1 created a gift
GIFTS: 13
Factory 0 is working..
GIFTS: 14
GIFTS: 15
Elf 2 created a gift
Elf 4 created a gift
Elf 0 created a gift
Factory 0 is working..
GIFTS: 16
GIFTS: 17
GIFTS: 18
Elf 1 created a gift
Elf 3 created a gift
GIFTS: 19
Factory 0 is working..
GIFTS: 20
Elf 4 created a gift
Elf 0 created a gift
Elf 2 created a gift
Rejecting Gift--820046672-4
Factory 0 is working..
Elf 4/0 is DONE
Elf 1 created a gift
Elf 3 created a gift
----------------Factory 0 FINISHED----------------
Rejecting Gift-1775300653-2
Rejecting Gift--906406470-0
Elf 2/0 is DONE
Rejecting Gift--778562716-3
Elf 0/0 is DONE
Elf 3/0 is DONE
Rejecting Gift-912276334-1
Elf 1 created a gift
Rejecting Gift--203717575-1
Elf 1 created a gift
Rejecting Gift--504209300-1
Elf 1 created a gift
Rejecting Gift--1405618643-1
Elf 1 created a gift
Rejecting Gift-472265871-1
Elf 1 created a gift
Rejecting Gift-1573561986-1
Elf 1 created a gift
Rejecting Gift-2005222080-1
Elf 1 created a gift
Rejecting Gift-1722629349-1
Elf 1 created a gift
Rejecting Gift-678251744-1
Elf 1 created a gift
Rejecting Gift--1911462918-1
Elf 1 created a gift
Rejecting Gift-994905496-1
Elf 1 created a gift
Rejecting Gift--1700057698-1
Elf 1 created a gift
Rejecting Gift-2040969141-1
Elf 1 created a gift
Rejecting Gift--135605836-1
Elf 1 created a gift
Rejecting Gift--1320452586-1

如您所见,始终有一个僵尸线程在运行。为什么会这样?

最佳答案

您的代码的问题是您希望使用 interupt() 方法取消/停止工作线程,但同时您正在调用线程上的方法,如果线程已经被中断并且该线程将抛出中断异常,并且这将清除中断状态。

举个例子,您的代码中可能会发生什么:

你的 Sprite 运行方法周期:

while (threadIsAlive()) {

1)           //dostuff -> while you are doing the stuff, supervisor call threadGroup.interrupt()
2)           awaitRandom();
}

1) 在你的 doStuff 代码中,supervisor 调用 threadGroup.interrupt(),这将在你的线程上设置中断状态,如果你调用 Thread.currentThread.isInterrupted() 你会得到 true

2)这里你调用了sleep()方法,如果在已经中断的线程上调用sleep方法会抛出InterruptedException,并且会清除中断状态! 检查javadoc:https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long) 因此,如果您调用 threadIsAlive() 方法 Thread.currentThread.isInterrupted() 将返回 false。

所以你可以做的就是在awaitRandom()(以及所有其他抛出InterruptedExceptions并清除中断状态的方法)方法中捕获interruptedException,并再次设置中断状态,如下所示:

 try {
            Thread.sleep(waitingTime);
        } catch (InterruptedException ex) {
    Thread.currentThread().interrupt(); //restores the interrupt status
}

但是更好的选择是通过其他机制而不是使用中断标志来取消/停止线程。您可以在工作线程中引入一些新的 volatile 标志停止变量(类似于您对 goalNotAchieved 所做的操作),如果您想取消/停止线程,可以设置此变量。

关于java - 线程组调用中断后留下僵尸线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53584777/

相关文章:

.net - 推荐.Net软实时

python - 如何启动连接到您正在监听的套接字的进程?

c++ - 由于使用事件而产生的开销

java - java中如何调用使用泛型类型的类?

java - URL参数字符串的正则表达式java

java - 透明 PNG 在 LWJGL 中不透明

android模拟器时间同步

java - SQLClientInfoException/Linux

java - java线程转储中的锁ID是什么意思

java - 使java类文件在线同步的任何方法