我有一个主管线程和一些工作线程。假设我们有 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/