Reputation: 3
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
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
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 unlock
ed 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