Search code examples
javamultithreadingsignalsrace-conditionreentrantlock

Signal Condition With No Waiting Threads


I'm using a ReentrantLock along with a Condition to synchronise two threads. Whenever the consumer threads performs an await() on the condition before the producer thread performs a signal(), things seem to work fine. However, when the producer thread performs a signal() before the consumer thread performs an await(), then the consumer thread just ends up waiting for ever. Is this supposed to happen or am I doing something wrong? What is the expected behaviour when a condition is signalled and there are no waiting threads?

Here's the code for the consumer:

this.lock.lock();
Log.d("websocket", "Sender acquired lock");
try
{
    Log.d("websocket", "Sender waiting for message from server");
    this.resultReady.await();
    Log.d("websocket", "Sender waking up");
    return this.result;

} catch (InterruptedException e)
{
    e.printStackTrace();
}
finally {
    this.lock.unlock();
}

Here's the code for the producer:

Log.d("websocket", "Receiver acquiring lock");
this.lock.lock();
Log.d("websocket", "Receiver acquired lock");
try
{
    Log.d("websocket", "Receiver setting result");
    result = serviceResult;
    Log.d("websocket", "Receiver waking up waiting threads");
    this.resultReady.signal();
} finally
{
    this.lock.unlock();
}

Solution

  • Is this supposed to happen or am I doing something wrong? What is the expected behaviour when a condition is signalled and there are no waiting threads?

    That's supposed to happen. There's no effect if there's no threads waiting. The Java doc says:

    Wakes up one waiting thread.

    If any threads are waiting on this condition then one is selected for waking up. That thread must then re-acquire the lock before returning from await.

    Surely if there's no threads to wake up, then there is no effect?

    You have a buffer, which contains one item, your result. You must test this result to be valid independently of the await() method. Or switch to something like a Semaphore which does have an internal state you can set.

    // Consumer
    this.lock.lock();
    Log.d("websocket", "Sender acquired lock");
    try
    {
        Log.d("websocket", "Sender waiting for message from server");
        while( result == null )   // CHANGE HERE
            resultReady.await();
        Log.d("websocket", "Sender waking up");
        return this.result;
    
    } catch (InterruptedException e)
    {
        e.printStackTrace();
    }
    finally {
        this.lock.unlock();
    }