Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kill a running thread in wait?

When i try to kill my Robber threads, some die , but some get stuck in the wait() block , what would be a better way to kill all the threads , or how do i get the blocked threads out to be killed?

private int robberId;
private static int robberGlobalId=0;
private TreasureChest chest;
private boolean alive = true;

public Robber(TreasureChest chest) {
    robberId = robberGlobalId;
    robberGlobalId++;

    this.chest = chest;
}

public void run() {
    while (alive) {
        try {
            synchronized(chest){
                robCoin();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("Robber " +robberId +" just died");
}

public void robCoin() throws InterruptedException {
    if (chest.getTreasureAmount() <= 0 ) {
        chest.wait();
    } else { 
        chest.removeCoin();
    }
    Thread.sleep(50);
}

public void killRobber() {
    alive = false;
}
like image 802
Dani Gilboa Avatar asked Feb 15 '23 23:02

Dani Gilboa


2 Answers

When i try to kill my Robber threads, some die , but some get stuck in the wait() block , what would be a better way to kill all the threads ,

The right way to "kill" a thread is to interrupt it with thread.interrupt(). If the thread is blocked in a wait(...) call, this will immediately throw InterruptedException. When you catch InterruptedException it is a good idea to immediately re-interrupt the thread to preserve the interrupt flag because when the exception is thrown, the interrupt bit is cleared.

try {
    ...wait();
} catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
    // handle the interrupt
    return;
}

Since not all methods throw InterruptedException, you can also check to make sure the thread has been interrupted with something like the following:

if (Thread.currentThread().isInterrupted()) {
    // stop processing
    return;
}

Or in your case something like:

while (alive && !Thread.currentThread().isInterrupted()) {

Btw, alive should be volatile because it looks to be accessed by multiple threads.

like image 74
Gray Avatar answered Feb 18 '23 23:02

Gray


Interrupting the thread is one way to do it as demonstrated in @Gray's answer, however it might be cleaner to wake up waiting threads when you "kill" the Robber instead of interrupting them.

In this example below the "Robber task" (implemented by the run() method) will wait as long as the robber is alive and the chest is empty ( less than or equal to 0). If killRobber() is called waiting threads are woken up and exit run() gracefully (alive will be false).

public void run() {
    try{
        synchronized(chest){
            while (chest.getTreasureAmount() <= 0 && alive) {
                chest.wait();
            } 
            if(alive){
                chest.removeCoin();
            }
        }
    }catch (InterruptedException ie){
        /* Thread interrupted do something appropriate,
           which may be to do nothing */
    }
}

public void killRobber() {
    synchronized(chest){
        alive = false;
        chest.notifyAll();
    }
}
like image 31
Dev Avatar answered Feb 18 '23 23:02

Dev