x Java Java 8 JUnit JSON
  • XML
  • JDBC Spring Boot Microservices React Contact Us

    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

    • One of the very powerful features of using Java lock is the ability to attempt (and fail) to acquire a lock. With traditional synchronization, once you hit a synchronized block, your thread either immediately acquires the lock or blocks until it can.
    • There is also a variation of the tryLock method that allows you to specify an amount of time you are willing to wait to acquire the lock.
    • Another benefit of the tryLock method is you can avoid deadlock. With traditional synchronization, you must acquire locks in the same order across all threads. You can always check if lock is acquired when using Java lock by calling tryLock.
    • One drawback of using Java lock is that you always follow the lock() method with a try-finally block, which releases the lock.

    References :
    Comments

    Leave a Reply

    Your email address will not be published. Required fields are marked *











    Share This