Muddassar Mubeen
Muddassar Mubeen

Reputation: 3

Interrupt called on a thread doesn't throw Interrupted Exception when the thread is blocking

I am trying to implement a blocking queue(only on consumer side) with ReentrantLock and conditions but am running into a state where the JVM doesn't terminate. The strange thing is that one thread gets interrupted but the other doesn't. I am sure I am making some mistake but just can't figure out what.

EDIT:

Main Question: Why does only one thread throw an interruptedexception when both the threads are blocking on condition.await

So the code below is just an example that i created. The main problem was to develop a producer-consumer implementation in which I had to create a simulation class which spawned two kinds of threads, customers and cooks, which were synchronized based on a Reentrant lock. After some operations were performed(customers adding orders and cooks performing serving those orders),I call join on customer threads to make sure that all orders have been processed and then to stop the cook threads, I called interrupt on the cook threads to terminate them. But only one thread throws interruptedexception and the second one doesn't. Why is that? since both the threads are blocking on await.

My code is as follows:

Thread class:

public class InterruptedThread implements Runnable{

    private final Lock lock;
    private final Condition condition;
    private final Queue<Integer> orderQueue;


    public InterruptedThread(Lock lock, Condition condition,Queue<Integer> orderQueue)
    {
        this.lock = lock;
        this.condition = condition;
        this.orderQueue = orderQueue;
    }

    @Override
    public void run() {

        try{
        while(true)
        {
            this.lock.lockInterruptibly();
            while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted())
            {
                   System.out.println("Inside blocking wait" + Thread.currentThread().getName());
                   condition.await();
            }

            int i = orderQueue.poll().intValue();
            System.out.println("Value read:" + i + "by thread" + Thread.currentThread().getName());
            this.lock.unlock();


        }
        }
        catch(InterruptedException ex)
        {
            System.out.println("Interrupted exception" + Thread.currentThread().getName());
            this.condition.signalAll();
            Thread.currentThread().interrupt();

        }

    }

}

Main class:

public class ExplicitLockCondition {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here

        Queue<Integer> orderQueue = new LinkedList<>();
        Lock lock = new ReentrantLock();
        Condition testCondition = lock.newCondition();

        Thread[] ths = new Thread[2];
        for(int i=0; i<ths.length;i++)
        {
            ths[i] = new Thread(new InterruptedThread(lock, testCondition,orderQueue));
            ths[i].start();
        }

        lock.lock();

        orderQueue.add(1);
        lock.unlock();

        lock.lock();
        orderQueue.add(2);
        lock.unlock();

        try {
            Thread.currentThread().sleep(5000);
        } catch (InterruptedException ex) {
            Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex);
        }

        lock.lock();
        orderQueue.add(-99);
        lock.unlock();


        for(int i=0; i<ths.length;i++)
        {
            ths[i].interrupt();

        }
        System.out.println("After loop exited!!!");
        for(int i=0; i<ths.length;i++)
        {
        System.out.println("Interrupted thread:" + ths[i].getName() +"with interrupt flag:" + ths[0].isInterrupted());
        }

        for(int i=0; i<ths.length;i++)
        {
            try {
                ths[i].join();
            } catch (InterruptedException ex) {
                Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        System.out.println("Program exited!!!");

    }

}

Upvotes: 0

Views: 1112

Answers (2)

Zielu
Zielu

Reputation: 8552

a) you never signal the condition after you insert a value to your queue

b) your thread will leave

while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted())

if it is interrupted, and then tried to poll the value from the queue. If there is no value there, the null will be returned and you end up with uncaught null pointer exception but the lock will never be unlock.

Allways

lock.lock()l
try {
...
} finally {
lovk.unlovk();

}

Upvotes: 0

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279880

You have

condition.await();

but the only place you signal it is in the catch block.

In a typical run of your application, your InterruptedThread (let's call it it1) will enter the while loop and await on the condition, putting itself in a waiting state. Your main thread will do a bunch of things and eventually interrupt it1. You'll note the javadoc of Condition#await() states

In all cases, before this method can return the current thread must re-acquire the lock associated with this condition.

So thread it2 reacquires the lock and because it's been interrupted

If the current thread:

  • has its interrupted status set on entry to this method; or
  • is interrupted while waiting and interruption of thread suspension is supported,

then InterruptedException is thrown and the current thread's interrupted status is cleared.

So execution leaves the while block and goes to the catch. During this time, your thread it2 still owns the lock, since nothing unlocked it. The catch block then calls

this.condition.signalAll();

which signals the condition. Thread it1 then completes normally. However, the Lock is still locked and nothing can acquire it which is why your other InterruptedThread cannot continue from within its

condition.await();

You basically have to manage locking and unlocking your Lock better.

Upvotes: 1

Related Questions