Search code examples
javamultithreadingwaitsynchronized

Is it possible for a thread to starve at wait() loop?


Suppose I have this method

/*1*/    public synchronized void method1() throws InterruptedException {
    
            while (condition)
 /*2*/           wait();


  /*3*/      notify();
      }

Suppose, we have a Thread 1 on the 2nd line wait condition, so Thread 1 would be in state WAITING.

Now Thread 2 enters, it doesn't satisfy the condition, so it bypasses the while loop and then Thread 2 calls notify in line 3, then Thread 1 should change its state from WAITING to BLOCKED, until the Thread 2 exits completely.

Suppose now, before Thread 2 exits completely, Thread 3 is BLOCKED outside the synchronized block to acquire the monitor.

Is it possible that Thread 3 acquires the lock before Thread 1 ? Can it be the same for Thread 4, and Thread 5 and so on? In that case, Thread-1 would be in the starving state.

Is this conceptually possible?

EDIT: How do I prevent starvation if this is the case?


Solution

  • How do I prevent starvation if this is the case?

    You cannot prevent it using synchronized keyword. However, you can use ReentrantLock instead because it allows "fair" locking

    private final ReentrantLock lock = new ReentrantLock(true); // fair lock
    private final Condition sync = lock.newCondition();
    
    public void method1() throws InterruptedException {
       lock.lock();
       try {
         while (condition)
           sync.await();
         sync.signal(); 
       } finally {
         lock.unlock();
       }
    }
    

    Keep in mind, that fair lock comes at price and you should have real reasons to use it

    From JavaDoc https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

    The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. Note however, that fairness of locks does not guarantee fairness of thread scheduling. Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. Also note that the untimed tryLock method does not honor the fairness setting. It will succeed if the lock is available even if other threads are waiting.