ReentrantLock

介绍

相对于synchronized,它具备如下特点

  • 可重入
  • 可中断
  • 可设置超时时间
  • 可设置公平锁
  • 支持多个条件变量

与synchronized一样,都支持可重入。

基本语法:

ReentrantLock lock = new ReentrantLock();
//获取锁
lock.lock();
try {
//临界区
    
}finally {
    //释放锁
    lock.unlock();
}

可重入

可重入是指同一个线程如果首次获得了这把锁,那么它是这把锁的拥有者,因此有权利再次获取这把锁。

    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        method1();
    }

    public static void method1(){
        lock.lock();
        try {
            System.out.println("method1");
            method2();
        }finally {
            lock.unlock();
        }

    }

    private static void method2() {
        lock.lock();
        try {
            System.out.println("method2");
        }finally {
            lock.unlock();
        }

    }

image-20210125164855075

如果不可重入,则在执行method2方法的时候就会被挡住,而method1和method2都成功执行,所以ReentrantLock具有可重入特性。

可打断

ReentrantLock.lockInterruptibly()方法:如果没有竞争,那么此方法就会获取lock锁,如果有竞争就会进入阻塞队列,可以被其他线程用interrupt打断。

    static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("尝试获取锁");
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                System.out.println("获取锁失败,返回");
                return;
            }
            try {
                System.out.println("获取到锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        t1.start();

        TimeUnit.SECONDS.sleep(2);

        System.out.println("打断t1");
        t1.interrupt();
    }

image-20210125170229257

锁超时

tryLock方法:一个有参,一个无参

image-20210125191743683

    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("尝试获取锁");
            try {
                if(!lock.tryLock(5, TimeUnit.SECONDS)){
                    System.out.println("获取锁失败,返回");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println("获取到锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        t1.start();
        TimeUnit.SECONDS.sleep(3);
        System.out.println("主线程释放锁");
        lock.unlock();
    }

image-20210125191939381

公平锁

ReentrantLock默认是不公平的。

可以通过它的构造方法设置公平性

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

条件变量

使用流程:

  • await前需要获得锁
  • await执行后,会释放锁,进入Condition中等待
  • await的线程被唤醒(或打断或超时)去重新竞争lock锁
  • 竞争lock锁成功后,从await后继续执行
    private static final Lock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();

    public static void main(String[] args) {
        new Thread(()->{
            try {
                lock.lock();
                System.out.println("在等一个信号"+Thread.currentThread().getName());
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally{
                System.out.println("拿到一个信号"+Thread.currentThread().getName());
                lock.unlock();
            }
        }).start();

        new Thread(()->{
            try {
                lock.lock();
                System.out.println("拿到锁"+Thread.currentThread().getName());
                condition.signalAll();
                System.out.println("发出了一个信号:"+Thread.currentThread().getName());
            } finally{
                lock.unlock();
            }
        }).start();
    }

image-20210125201244727

原文地址:https://www.cnblogs.com/wwjj4811/p/14327173.html