xbmono
xbmono

Reputation: 2316

How does await() and signal() work inside lock block?

So for my own understanding, I wrote two threads each of which prints a line to output. However, I wanted to make the two threads so that they print one after another. Let's say t1 and t2. If t1 prints its own message then it has to wait for the other thread to print theirs. Now I manage to make it working by experimenting but there is something I don't understand.

This is my code:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Multithread {
  
    public static void main(String [] m) throws InterruptedException, ExecutionException {
        Lock lock = new ReentrantLock();
        Condition c1 = lock.newCondition();
    
        Runnable t1 = new Runnable() {
            
            @Override
            public void run() {
                for(int i : new int[] {1,2,3,4,5}) {
                    lock.lock();
                    try {
                        c1.signal();
                        System.out.println("In thread 1 - " + i);
                        
                        try {
                            c1.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } finally {
                        c1.signal();
                        lock.unlock();
                    }
                }
                
            }
        };
        
        
        Callable<String> t2 = new Callable<String>() {

            @Override
            public String call() throws Exception {
                for(int i : new int[] {1,2,3,4,5}) {
                    lock.lock();
                    try {
                        c1.signal();
                        System.out.println("In callable 2 - " + i);
                        try {
                            c1.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } finally {
                        c1.signal();
                        lock.unlock();
                    }
                }

                return "This is callable";
            }
            
        };
        
        new Thread(t1, "t1").start();
        FutureTask<String> task = new FutureTask<>(t2);
        new Thread(task, "t2").start();
        //c1.signalAll();
        System.out.println(task.get());
        
    }
}

Please ignore the code is used Callable and Runnable instead of using one type. So this is my interpretation of this code:

But to my surprise, it works as I wanted to and each thread prints its message on a turn basis, that is:

Another thing that I don't understand is the fact that InterruptedException never happens and the printStackTrace() never reached!

Can someone please explain what is happening here?

Upvotes: 0

Views: 856

Answers (1)

Solomon Slow
Solomon Slow

Reputation: 27190

With this logic, t2 should never print its message because t1 is waiting and hasn't unlock() ed

I think what you're missing is that condition.await() unlocks the lock from which condition was obtained, and then it guarantees to re-lock the lock before it returns.

Upvotes: 1

Related Questions