程序笔记   发布时间:2022-07-20  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了ReentrantLock 基本使用大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_489_0@ReentrantLock 是在 java.util.concurrent 并发工具包下的一个重要工具类,相对于 synchronized 它具备如下特点:

  • 可中断
  • 可以设置超时时间
  • 可以设置为公平锁
  • 支持多个条件变量
@H_489_0@与 synchronized 一样,都支持可重入(同一个线程多次获取同一把锁)。

@H_489_0@下面是一个获取锁的基本方式:

public class SharedObject {
    ReentrantLock lock = new ReentrantLock();

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

可打断

@H_489_0@ReentrantLock#lock() 方法和 synchronized 获取锁的时候是一样的,会一直等待(不可打断)直到获取了锁;而可打断的意思是说,打断你获取锁;就是说不用你获取锁了。

@H_489_0@如果你允许获取锁的时候被被人打断,那么可以使用 ReentrantLock#lockInterruptibly() 方法获取锁。当别的线程调用了 interrupt() 方法时,该方法就会抛出异常。

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
    log.debug("启动...");
    try {
        lock.lockInterruptibly();
    } catch (InterruptedException E) {
        e.printStackTrace();
        log.debug("等锁的过程中被打断");
        return;
    }
    try {
        log.debug("获得了锁");
    } finally {
        lock.unlock();
    }
}, "t1");

lock.lock();
log.debug("获得了锁");
t1.start();
try {
    sleep(1);
    t1.interrupt();
    log.debug("执行打断");
} finally {
    lock.unlock();
}

锁超时

@H_489_0@就是说,多长时间内没有获取到锁,就不获取锁了。而想要打到这个效果,就需要使用 ``ReentrantLock#tryLock()` 方法,如果使用无参方法,则没有获取到锁后直接返回;如果使用带参方法,则超过指定时间后还没有取到锁则返回。

@H_489_0@指的注意的是:tryLock(..) 也是支持可中断的。

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("获得了锁");

t1.start();
try {
    sleep(2);
} finally {
    lock.unlock();
}

公平锁

@H_489_0@ReentrantLock 默认是非公平锁。

ReentrantLock lock = new ReentrantLock(false);
lock.lock();
for (int i = 0; i < 500; i++) {
    new Thread(() -> {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " running...");
        } finally {
            lock.unlock();
        }
    }, "t" + i).start();
}

// 1s 之后去争抢锁
Thread.sleep(1000);
new Thread(() -> {
    System.out.println(Thread.currentThread().getName() + " start...");
    lock.lock();
    try {
        System.out.println(Thread.currentThread().getName() + " running...");
    } finally {
        lock.unlock();
    }
}, "强行插入").start();
lock.unlock();

条件变量

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

@H_489_0@ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比 synchronized 是那些不满足条件的线程都在一间休息室等消息,而 ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤醒。

@H_489_0@使用要点:

  • await 前需要获得锁
  • await 执行后,会释放锁,进入 conditionObject 等待
  • await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁
  • 竞争 lock 锁成功后,从 await 后继续执行
static ReentrantLock lock = new ReentrantLock();
static Condition waitCigaretteQueue = lock.newCondition();
static Condition waitbreakfastQueue = lock.newCondition();
static volatile Boolean hasCigrette = false;
static volatile Boolean hasBreakfast = false;
public static void main (String[]args){
    new Thread(() -> {
        try {
            lock.lock();
            while (!hasCigrettE) {
                try {
                    waitCigaretteQueue.await();
                } catch (InterruptedException E) {
                    e.printStackTrace();
                }
            }
            log.debug("等到了它的烟");
        } finally {
            lock.unlock();
        }
    }).start();

    new Thread(() -> {
        try {
            lock.lock();
            while (!hasBreakfast) {
                try {
                    waitbreakfastQueue.await();
                } catch (InterruptedException E) {
                    e.printStackTrace();
                }
            }
            log.debug("等到了它的早餐");
        } finally {
            lock.unlock();
        }
    }).start();
    sleep(1);
    sendBreakfast();
    sleep(1);
    sendCigarette();
}

private static void sendCigarette () {
    lock.lock();
    try {
        log.debug("送烟来了");
        hasCigrette = true;
        waitCigaretteQueue.signal();
    } finally {
        lock.unlock();
    }
}

private static void sendBreakfast () {
    lock.lock();
    try {
        log.debug("送早餐来了");
        hasBreakfast = true;
        waitbreakfastQueue.signal();
    } finally {
        lock.unlock();

    }
}
@H_489_0@也就是可以创建多个 Condition,将线程放入不同的 Condition 中进行等待,可以随机唤醒 Condition 中的一个线程或唤醒所有线程。

大佬总结

以上是大佬教程为你收集整理的ReentrantLock 基本使用全部内容,希望文章能够帮你解决ReentrantLock 基本使用所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。