Talk about Lock

Get into the habit of writing together! This is the first day of my participation in the "Nuggets Daily New Plan·April Update Challenge",Click to view event details

1 Introduction

lock is an interface, it has many implementations, the common ones are reentrant lock (ReentrantLock) and read-write lock (Read, WriteLock), in a sub-package locks package under JUC. Lock needs to acquire and release locks explicitly. Although it is not as convenient as acquiring locks implicitly, it has synchronization features such as operability of lock acquisition and release, interruptible acquisition of locks, and timeout acquisition of locks.

image-20220411135241875

1.1- Introduction to the method

  • void lock(): acquire the lock, if the lock is not available, the current thread will block until the lock is acquired;

    This is the simplest and most common way to acquire a lock. It does not automatically release the lock when an exception occurs like synchronized, so it must be released in the finally block to ensure that the lock can be released normally when an exception occurs. It should be noted that this method cannot be interrupted, so if it is in a deadlock situation lock() will wait forever.

  • void lockInterruptibly() throws InterruptedException: Acquires an interruptible lock, and returns when it is interrupted or the lock is acquired. If the lock is unavailable, the current thread is blocked until the lock is acquired or interrupted;

    Unlike lock(), lockInterruptibly() supports interruption while waiting for the lock, or it can be said that lockInterruptibly responds to the Thread.interrupt method with a higher priority. When lockInterruptibly calls the interruption method while waiting for the lock, lockInterruptibly does not. Acquiring the lock instead throws an InterruptedException. And lock() is the priority to acquire the lock before responding to the interrupt. It is useless to execute interrupt while the lock is waiting. It must wait until the lock acquires the lock before responding to the interrupt.

  • boolean tryLock(): try to acquire the lock and return immediately; true: acquire the lock successfully; false: acquire the lock failed;

  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException:尝试在指定的超时时间获取锁,当获取到锁时返回true;当超时或被中断时返回false;

  • Condition newCondition():返回一个和锁绑定的条件队列;在等待条件之前线程必须先获取当前锁,同时await()方法会原子地释放锁,并在返回之前重新获取到锁;

  • void unlock():释放锁;

ReentrantLock和ReadWriteLock是此接口的实现:

image-20220411140005843

2.Lock锁的意义

  1. 对比于更加古老的synchronized锁,lock锁的操作更加的灵活,Lock提供了更丰富的锁操作
  2. 通常来说锁的作用是提供多线程对共享资源的独占访问,一次只能由一个线程获得锁,只有获得锁的线程拥有对共享资源的访问权限,但是有些所可以做到对共享资源的并发访问,比如读写锁可以并发的读共享资源。

3.用法

下面的代码是一个基本的示例,声明一个Lock锁的实例对象,调用lock方法加锁,与synchronized自动解锁所不同的是Lock需要手动释放锁,正是如此是的lock锁有了很强大的灵活性。

Lock lock = new ReentrantLock();
lock.lock();
try{
  
}finally {
  lock.unlock();
}
复制代码

3.1-Condition 的用法

关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock 锁的 newContition()方法返回的 Condition 对象也可以实现等待/通知模式。 用 notify()通知时,JVM 会随机唤醒某个等待的线程, 而使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:

  • await() : The current thread will wait and the lock will be released at the same time. When other threads call signal()the method, the sleeping thread will regain the lock and continue to execute the code (wake up where it is sleeping).
  • signal() : used to wake up a waiting thread.

It should be noted that before calling the await()/signal() method of Condition, the thread also needs to hold the relevant Lock lock. After calling await(), the thread will release the lock. In the waiting queue of the object, a thread is awakened, and the awakened thread starts to try to acquire the lock, and continues to execute once the lock is successfully acquired.

class Share {
//通过两个线程对number进行加减操作,一个线程当number == 0时 对number++,另外一个线程当number == 1时对number--
    private Integer number = 0;
    private ReentrantLock lock = new ReentrantLock();
    private Condition newCondition = lock.newCondition();
    // number++
    public void incr() {
        try {
            lock.lock(); // 加锁
            while (number != 0) {
                newCondition.await();//沉睡
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            newCondition.signal(); //唤醒另一个沉睡的线程 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    // number--
    public void decr() {
        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();
        /**out:
         * AA::1
         * BB::0
         * AA::1
         * BB::0
         * .....
         */     
    }
}
复制代码

Guess you like

Origin juejin.im/post/7085252554665230350