Java Multithreading: Re-entrant Locks (Video Tutorial Part 10)

How to use the ReentrantLock class in Java as an alternative to synchronized code blocks. ReentrantLocks let you do all the stuff that you can do with synchronized, wait and notify, plus some more stuff besides that may come in handy from time to time.

After starting the video, click the maximise button to make it fullscreen so you can see the code!



Code For This Tutorial



The main program just runs the firstThread() and secondThread() methods in different threads. finish() is called after both threads finish.

 
import java.util.Scanner;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Runner {

    private int count = 0;
    private Lock lock = new ReentrantLock();
    private Condition cond = lock.newCondition();

    private void increment() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

    public void firstThread() throws InterruptedException {
        lock.lock();
        
        System.out.println("Waiting ....");
        cond.await();
        
        System.out.println("Woken up!");

        try {
            increment();
        } finally {
            lock.unlock();
        }
    }

    public void secondThread() throws InterruptedException {
        
        Thread.sleep(1000);
        lock.lock();
        
        System.out.println("Press the return key!");
        new Scanner(System.in).nextLine();
        System.out.println("Got return key!");
        
        cond.signal();

        try {
            increment();
        } finally {
            lock.unlock();
        }
    }

    public void finished() {
        System.out.println("Count is: " + count);
    }
}

 
Waiting ....
Press the return key!

Got return key!
Woken up!
Count is: 20000




The main program (just creates and runs two threads):

 

public class App {

    
    public static void main(String[] args) throws Exception {
        
        final Runner runner = new Runner();
        
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.firstThread();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.secondThread();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
        
        runner.finished();
    }

}