How to acquire Lock in Java
Below are the examples of how to acquire lock in Java
1) Acquire a lock in Java using synchronized keyword
In below example, you can see that when one thread (Thread-0) is executing setCounter() method, other thread (Thread-1) cannot enter other synchronized method getCounter().
public class Counter { private int counter; public synchronized int getCounter() { System.out.println(Thread.currentThread().getName() + " in getCounter method"); return counter; } public synchronized void setCounter(int counter) { System.out.println(Thread.currentThread().getName() + " in setCounter method"); this.counter = counter; try { Thread.sleep(2000); // takes lock with it } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Counter counter = new Counter(); Thread t1 = new Thread(() -> { for (int i=0; i<5; i ++) { counter.setCounter(i++); } }); Thread t2 = new Thread(() -> { for (int i=0; i<5; i ++) { System.out.println("Counter value " + counter.getCounter()); } }); t1.start(); t2.start(); } }
Output :
Thread-0 in setCounter method Thread-0 in setCounter method Thread-1 in getCounter method Thread-0 in setCounter method Counter value 2 Thread-1 in getCounter method Counter value 4 Thread-1 in getCounter method Counter value 4 Thread-1 in getCounter method Counter value 4 Thread-1 in getCounter method Counter value 4
2) Acquire a lock in Java using ReentrantLock lock()
A thread can also acquire a lock on a block of code using java.util.concurrent.locks.ReentrantLock lock() method.
It has following signature : public void lock() & it acquires the lock if it is not held by
another thread and returns immediately.
In below example multiple threads cannot execute the block of code of instance for which lock has been acquired.
It is recommended that you always follow the lock() method with a try-finally block, which releases the lock.
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Producer { private String data; public void produce() { data = "data"; } } public class MyThread implements Runnable { private Producer producer; private Lock lock = new ReentrantLock(); public MyThread(Producer producer) { this.producer = producer; } public void run() { try { lock.lock(); // blocks until acquired System.out.println(Thread.currentThread().getName() + " running"); producer.produce(); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) { MyThread myThread = new MyThread(new Producer()); Thread threadOne = new Thread(myThread); Thread threadTwo = new Thread(myThread); Thread threadThree = new Thread(myThread); threadOne.start(); threadTwo.start(); threadThree.start(); } }
Output :
Thread-1 running Thread-0 running Thread-2 running
3) Acquire a lock in Java using ReentrantLock tryLock()
The previous example doesn't really provide a compelling reason for you to choose to use a Lock instance instead of traditional
synchronization. One of the very powerful features is the ability to attempt (and fail) to acquire a lock.
A thread can also acquire a lock on a block of code using java.util.concurrent.locks.ReentrantLock tryLock() method.
It has following signature : public boolean tryLock() & it acquires the lock only if it
is not held by another thread at the time of invocation.
In below example multiple threads cannot execute the block of code of instance for which lock has been acquired.
However those threads will not be blocked and could do something else in the meantime.
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Producer { private String data; public void produce() { data = "data"; } } public class MyThread implements Runnable { private Producer producer; private Lock lock = new ReentrantLock(); public MyThread(Producer producer) { this.producer = producer; } public void run() { boolean locked = false; try { locked = lock.tryLock(); // try without waiting if (locked) { System.out.println(Thread.currentThread().getName() + " running"); producer.produce(); Thread.sleep(2000); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (locked) { lock.unlock(); } } } public static void main(String[] args) { MyThread myThread = new MyThread(new Producer()); Thread threadOne = new Thread(myThread); Thread threadTwo = new Thread(myThread); Thread threadThree = new Thread(myThread); threadOne.start(); threadTwo.start(); threadThree.start(); } }
Output :
Thread-0 running
Java lock vs synchronized