线程组调用中断后留下一个僵尸线程
Thread group leaves a zombie thread after calling interrupt
我有一个主管线程和几个工作线程。让我们假设我们有小精灵将礼物打包并送到工厂,工厂将它们排在队列中。赠送一定数量后,主管叫停
我所有的工作线程都属于一个线程组。当监督者意识到已经达到所需的礼物数量时,它会调用 workersThreadGroup.interrupt()。但是,总有一个僵尸工人在继续生产。
现在,对于一些代码:
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
如您所见,始终存在一个僵尸线程运行。为什么会这样?
你的代码的问题是你想 cancel/stop 你的工作线程使用 interupt() 方法,但同时你在线程上调用方法,如果线程已经中断,这将清除中断状态。
举个例子,您的代码中会发生什么:
你的精灵运行方法循环:
while (threadIsAlive()) {
1) //dostuff -> while you are doing the stuff, supervisor call threadGroup.interrupt()
2) awaitRandom();
}
1) 在你的 doStuff 代码中,主管调用 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() 将 return false.
所以你可以做什么,你可以在 awaitRandom()(以及所有其他抛出 InterruptedExceptions 并清除中断状态的方法)方法中捕获 interrputedException 并再次设置中断状态,如下所示:
try {
Thread.sleep(waitingTime);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt(); //restores the interrupt status
}
但更好的选择是 cancel/stop 线程通过某种不同于中断标志的机制。您可以在您的工作线程中引入一些新的易失性标志停止变量(与您对 goalNotAchieved 所做的类似),如果您想要 cancel/stop 线程,则可以设置此变量。
我有一个主管线程和几个工作线程。让我们假设我们有小精灵将礼物打包并送到工厂,工厂将它们排在队列中。赠送一定数量后,主管叫停
我所有的工作线程都属于一个线程组。当监督者意识到已经达到所需的礼物数量时,它会调用 workersThreadGroup.interrupt()。但是,总有一个僵尸工人在继续生产。
现在,对于一些代码:
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
如您所见,始终存在一个僵尸线程运行。为什么会这样?
你的代码的问题是你想 cancel/stop 你的工作线程使用 interupt() 方法,但同时你在线程上调用方法,如果线程已经中断,这将清除中断状态。
举个例子,您的代码中会发生什么:
你的精灵运行方法循环:
while (threadIsAlive()) {
1) //dostuff -> while you are doing the stuff, supervisor call threadGroup.interrupt()
2) awaitRandom();
}
1) 在你的 doStuff 代码中,主管调用 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() 将 return false.
所以你可以做什么,你可以在 awaitRandom()(以及所有其他抛出 InterruptedExceptions 并清除中断状态的方法)方法中捕获 interrputedException 并再次设置中断状态,如下所示:
try {
Thread.sleep(waitingTime);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt(); //restores the interrupt status
}
但更好的选择是 cancel/stop 线程通过某种不同于中断标志的机制。您可以在您的工作线程中引入一些新的易失性标志停止变量(与您对 goalNotAchieved 所做的类似),如果您想要 cancel/stop 线程,则可以设置此变量。