java并发学习23:ReentrantLock介绍使用
发布日期:2021-05-07 02:04:34 浏览次数:17 分类:精选文章

本文共 3633 字,大约阅读时间需要 12 分钟。

1、与synchronized相比

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

与synchronized一样,都支持可重入

基本语法:

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

2、可重入

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

如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住

static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {       method1();}public static void method1() {       lock.lock();    try {           log.debug("execute method1");        method2();      } finally {           lock.unlock();       }}public static void method2() {       lock.lock();    try {           log.debug("execute method2");        method3();        } finally {           lock.unlock();     }}public static void method3() {       lock.lock();    try {           log.debug("execute method3");     } finally {           lock.unlock();     }}

3、可打断

lock.lockInterruptibly();//获取锁,同时可以被其他线程打断

static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {       new Thread(() -> {          method1();      },"t1")}public static void method1() {       //如果没有竞争那么方法就会获取lock对象锁    //如果没有竞争就进入阻塞队列,可以被其他线程用interrupt 方法打断    lock.lockInterruptibly();    try {           log.debug("execute method1");        method2();      } finally {           lock.unlock();       }}

4、锁超时

4.1 立刻失败
ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {       log.debug("启动...");    if (!lock.tryLock()) {           log.debug("获取立刻失败,返回");        return;      }    try {           log.debug("获得了锁");     } finally {           lock.unlock();    }}, "t1");lock.lock();log.debug("获得了锁")

4.2 超时失败

ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {       log.debug("启动...");    try {           if (!lock.tryLock(1, TimeUnit.SECONDS)) {               log.debug("获取等待 1s 后失败,返回");            return;               }       } catch (InterruptedExceptione) {           e.printStackTrace();     }    try {           log.debug("获得了锁");       } finally {           lock.unlock();    }}, "t1");lock.lock();log.debug("获得了锁");t1.start();try {       sleep(2);} finally {       lock.unlock();}

4.3tryLock解决哲学家问题

class Chopstick extends ReentrantLock {       String name;    public Chopstick(Stringname) {           this.name=name;       }    @Override    public String toString() {           return"筷子{"+name+'}';        }}class Philosopher extends Thread {   	Chopstick left;    Chopstick right;    public Philosopher(Stringname, Chopstickleft, Chopstickright) {   	super(name);        this.left=left;        this.right=right;      }        @Override    public void run() {           while (true) {               // 尝试获得左手筷子            if (left.tryLock()) {                   try {                       // 尝试获得右手筷子                    if (right.tryLock()) {                           try {                               eat();                          } finally {                               right.unlock();                          }                                  }                         } finally {                       left.unlock();                     }                  }            }      }        private void eat() {           log.debug("eating...");        Sleeper.sleep(1);       }}

4.4 公平锁

ReentrantLock默认是不公平的。(谁抢到就是谁的,所以是不公平的)synchronized也是不公平的。

4.5 条件变量

synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入 waitSet 等

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比

  • synchronized 是那些不满足条件的线程都在一间休息室等消息
  • 而 ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤醒

要点:

  • await 前需要获得锁
  • await 执行后,会释放锁,进入 conditionObject 等待
  • await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁
  • 竞争 lock 锁成功后,从 await 后继续执行
上一篇:java并发学习24:固定运行顺序模式
下一篇:java并发学习22:多把锁与活跃性

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月01日 16时19分25秒