This chapter explains how to use Lock, including reentrant Lock and read-write Lock. Lock and Synchronized. Multithreading has been the difficulty in Java development, but also in the interview of frequent, while there is still time, I intend to consolidate the JUC knowledge, I think the opportunity is everywhere, but is always left to prepare for the people, I hope we can come on!!

Go down, come up again, I think we’ll be different.

The sun is just right and the home feels really comfortable

JUC series

  • What is JUC?
  • JUC series (ii) Review Synchronized keyword
  • JUC series (three) Lock Lock mechanism detail code theory combined
  • The thread safety problem of JUC series (4)
  • JUC series (5) | Synchonized keywords to further explain
  • JUC series (6) | Callable and interface explanation & use, FutureTask application Future
  • JUC series (7) | JUC three commonly used tools CountDownLatch, CyclicBarrier, Semaphore
  • JUC series (8) | read-write lock – ReadWriteLock

Is being continuously updated…

What is Lock

The Lock Lock implementation provides a wider range of Lock operations than can be obtained using synchronized methods and statements.

Two, lock type

Reentrant lock: All synchronized methods in the execution object do not acquire the lock again

Interruptible lock: Interruptible while waiting to acquire the lock

Fair lock: The lock is acquired according to the waiting time of the thread. If the waiting time is long, the thread has the priority to obtain the lock

Read/write lock: Read and write resources are divided into two parts. Multiple threads can read and write resources simultaneously

Lock interface

public interface Lock {

    void lock(a); // Get the lock.

    /** The lock is acquired unless the current thread is interrupted. If available, the lock is acquired and returned immediately. If the lock is not available, the current thread is disabled for thread scheduling purposes and sleeps until one of two things happens: the lock is acquired by the current thread; Or some other thread interrupts the current thread, enabling the interrupt to acquire the lock. If the current thread: sets the disconnection state when entering this method; Either interrupt lock acquisition, support interrupt lock acquisition, */
    void lockInterruptibly(a) throws InterruptedException; 

    /** The lock is only acquired when the call is idle. If available, the lock is acquired and a value of true is returned immediately. This method returns false immediately if the lock is not available. * /
    boolean tryLock(a);
    
    // Wait one more time than above
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;  

   	/ / unlock
    void unlock(a); 
    
    // Returns a new Condition instance bound to this Lock instance.
    Condition newCondition(a);  。
}
Copy the code

Here are some common methods to use.

3.1. Lock (), unlock ()

Lock () is one of the most common methods used to acquire the lock, and if the lock has already been acquired by another thread, the current thread is disabled for thread scheduling and sleeps, waiting until the lock is acquired.

If you use lock, you must actively release the lock. Even if an exception occurs, you also need to actively release the lock, because lock is not automatically released like synchronized. When using a lock, you must do it ina try{}catch(){} and place the lock release code in finally{} to ensure that the lock will be released.

Unlock () actively releases the lock.

The lock interface type has several implementation classes, here is a random ha.

Lock lock = new ReentrantLock();
try {
    lock.lock();
    System.out.println("Locked up.");
}catch (Exception e){
    e.printStackTrace();
}finally {
    lock.unlock();
    System.out.println("Unlocked");
}
Copy the code

3.2, newCondition

Synchronized is used with wait()/notify() to implement wait /notify mode. The Lock newContition() method returns Condition, The Condition class can also implement the wait/notification pattern. With notify(), the JVM wakes up a waiting thread at random. Condition can be used for selective notification. Condition has two common methods:

  • await(): causes the current thread to wait and releases the lock until another thread callssignal()Method, the sleeping thread regains the lock and continues executing the code (waking up where it was sleeping).
  • Signal () : Wakes up a waiting thread.

Note: The thread is also required to hold the associated Lock Lock before calling the await()/signal() method of Condition. The Lock is released after calling await(). A thread is awakened from the current Condition waiting queue after calling singal(). The awakened thread attempts to acquire the lock, and once it has successfully acquired it continues.

Here’s an example of how to write it in code:

I won’t give you an example of synchronized implementation, which is pretty much the same.

Example: We have two threads implementing the number variable with an initial value of 0. One thread implements the number value +1 when number = =0, and the other thread implements the number-1 when number = = 1.

class Share {

    private Integer number = 0;

    private ReentrantLock lock = new ReentrantLock();

    private Condition newCondition = lock.newCondition();

    // The +1 method
    public void incr(a) {
        try {
            lock.lock(); / / lock
            while(number ! =0) {
                newCondition.await();/ / into a deep sleep
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "... "" + number);
            newCondition.signal(); // Wake up another sleeping thread
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ lock.unlock(); }}// The method of -1
    public void decr(a) {
        try {
            lock.lock();
            while(number ! =1) {
                newCondition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "... "" + number);
            newCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ lock.unlock(); }}}public class LockDemo2 {
    public static void main(String[] args) {
        Share share = new Share();

        new Thread(()->{
            for (int i=0; i<=10;i++){
                share.incr();
            }
        },"AA").start();

        new Thread(()->{
            for (int i=0; i<=10;i++){
                share.decr();
            }
        },"BB").start();
        /** * AA::1 * BB::0 * AA::1 * BB::0 * ..... * /}}Copy the code

ReentrantLock (ReentrantLock)

ReentrantLock stands for “ReentrantLock”. ReentrantLock is the only class that implements the Lock interface, and ReentrantLock provides many more methods.

Reentrant lock: What is “reentrant”? Reentrant means that a thread that has acquired a lock can acquire it again without deadlock.

package com.crush.juc02;

import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    lock.lock();
                    System.out.println(The first time the lock is acquired, the lock is: + lock);
                    for (int i = 2; i<=11; i++){try {
                            lock.lock();
                            System.out.println("The first" + i + "Second fetch lock, this lock is:" + lock);
                            try {
                                Thread.sleep(new Random().nextInt(200));
                            } catch(InterruptedException e) { e.printStackTrace(); }}finally {
                           lock.unlock();// If you comment this out, the program will be deadlocked.}}}finally {
                    lock.unlock();
                }
            }
        }).start();

		new Thread(new Runnable() {

			@Override
			public void run(a) {
				try {
					lock.lock();
                    System.out.println("Here's the thread that wrote one more to test for deadlocks.");
				} finally{ lock.unlock(); } } }).start(); }}/ * * * first acquiring a lock, the lock is: Java. Util. Concurrent. The locks. Already @ 6 b5fde1f [Locked by thread thread - 0] * second acquiring a lock, the lock is: Java. Util. Concurrent. The locks. Already @ 6 b5fde1f [Locked by thread thread - 0] * 3 time acquiring a lock, the lock is: java.util.concurrent.locks.ReentrantLock@6b5fde1f[Locked by thread Thread-0] * ... * /
Copy the code

With deadlocks, programs cannot be stopped until they run out of resources or terminate voluntarily.

The code also mentions the concept of deadlocks, which must be unlocked manually in order to avoid deadlocks.

5. ReadWriteLock

ReadWriteLock is also an interface in which only two methods are defined:

public interface ReadWriteLock {
	
    // Get read lock
    Lock readLock(a);

	// Get the write lock
    Lock writeLock(a);
}
Copy the code

It is divided into a read lock and a write lock. The read and write locks are separated so that multiple threads can perform read operations, improving efficiency.

ReentrantReadWriteLock Implements the ReadWriteLock interface. There are more methods available, but the main one is to get writeLock and readLock.

5.1, case

If multiple threads want to read, we use Synchronized.

public class SynchronizedDemo2 {

    public static void main(String[] args) {
        final SynchronizedDemo2 test = new SynchronizedDemo2();
        new Thread(()->{
            test.get(Thread.currentThread());
        }).start();

        new Thread(()->{
            test.get(Thread.currentThread());
        }).start();
    }

    public synchronized void get(Thread thread) {
        long start = System.currentTimeMillis();
        while(System.currentTimeMillis() - start <= 1) {
            System.out.println(thread.getName()+"Reading in progress");
        }
        System.out.println(thread.getName()+"Read operation completed"); }}/** * output * Thread-0 is reading * Thread-0 Is reading * Thread-1 is reading * Thread-1 is reading *.... * Thread-1 Complete */
Copy the code

Change to read and write lock

public class SynchronizedDemo2 {

    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        final SynchronizedDemo2 test = new SynchronizedDemo2();
        new Thread(()->{
            test.get2(Thread.currentThread());
        }).start();

        new Thread(()->{
            test.get2(Thread.currentThread());
        }).start();
    }

    public void get2(Thread thread) {
        rwl.readLock().lock();
        try {
            long start = System.currentTimeMillis();
            while(System.currentTimeMillis() - start <= 1) {
                System.out.println(thread.getName()+"Reading in progress");
            }
            System.out.println(thread.getName()+"Read operation completed");
        } finally{ rwl.readLock().unlock(); }}}/** * output * Thread-0 reading operation * Thread-0 reading operation completed * Thread-1 reading operation completed */
Copy the code

Conclusion: Thread 1 and thread 2 read simultaneously after using read/write lock, we can experience a significant improvement in efficiency.

Note:

  1. If one thread has occupied the read lock, another thread can apply for the read lock. However, if another thread applies for the write lock, it can obtain the read lock only after the read lock is released.
  2. If a thread has already occupied the write lock, other threads can apply for the write lock or read lock only when the thread holding the write lock releases the write lock.

Lock and Synchronized

category synchronized Lock
There are levels Java keywords, at the JVM level It’s an interface
To acquire the lock Suppose thread A acquires the lock and thread B waits. If thread A blocks, thread B will wait Depending on the situation, a Lock can be acquired in multiple ways. The thread can attempt to acquire the Lock without waiting forever
The release of the lock When a synchronized method or block of synchronized code completes execution, the system automatically lets the thread release the lock (manual release is not required). If an exception occurs, the JVM lets the thread release the lock In finally, the lock must be released, otherwise threads are likely to deadlock (manually release the lock)
The lock state Unable to determine Can be judged
The lock type The lock type Reentrant, judge, fair (both)
performance Premise: Synchronization efficiency is low in a large number of threads Premise: The synchronization efficiency is much higher than synchronized in the case of a large number of threads

Lock improves the efficiency of read operations by multiple threads.


Seven, talk to yourself

Recently, I started to learn JUC again. I feel there is a lot of Java content, but I still think I need to lay a solid foundation in order to go further.

Is continuing to update, if you feel helpful to you, also interested in words, pay attention to me, let us study together, discuss together.

Hello, I am ning Zhichun, a blogger, a small seed on the way of Learning Java. I also hope that one day I can take root and grow into a tree in the sky.

Hope to share with you 😁

By the time we meet again, we have achieved something.