ReentrantLock与Synchronized
ReentrantLock重入锁
reentrantLock是一种显式锁,与synchronized隐式锁对应,ReentrantLock实现基于AQS(AbstractQueueSynchronizer:队列同步器)通过对tryAcquire和tryRelease的重写实现了锁机制和重入机制,默认非公平锁.
方法 | 说明 |
---|---|
lock | 获取锁,如果锁不可用,那么当前线程会休眠直到获取到锁为止 |
lockInterruptibly | 可中断地获取锁,如果当前线程发生interrupt,则释放锁 |
unlock | 释放锁 |
newCondition | 创建一个当前锁的条件监视器Condition,Condition实例用于控制当前Lock的线程队列的notify和wait |
互斥锁(Mutex lock):通过阻塞线程来加锁,中断阻塞来解锁;
synchronized与ReentrantLock的优劣
ReentrantLock获得锁和释放锁的操作更加灵活,且具备独立的条件监视器,等待和唤醒线程的操作也更加方便和多样,在多线程情况下ReentrantLock效率比synchronized更高.
synchronized具备完备的语义,一个获取锁的操作一定会对应一个释放锁的操作,使用更加方便,简单.
ReentrantLock的条件监视器
Condition即条件,其在AQS中起到监视器(monitor)的作用,监视器用于监控一段同步的代码块,可以用于线程的阻塞和解除阻塞.
每当条件监视器增加一个等待线程的时候,该线程也会进入一个条件等待队列,下次signal方法调用的时候,会从队列里获取节点挨个唤醒.
方法 | 说明 |
---|---|
await | 当前线程进入等待状态,直到响应通知(signal)或者中断(Interrupt) |
awaitUninterruptibly | 当前线程进入等待状态,直到响应通知(signal) |
awaitNanos(long) | 指定一个单位为纳秒的超时时长,当前线程进入等待状态,直到响应通知,中断或超时,返回值为剩余时长,小于0则超时 |
awaitUntil(Date) | 指定一个超时时刻,当前线程进入等待状态,直到响应通知,中断或者超时 |
signal/signalAll | 对condition队列中的线程进行唤醒/唤醒全部 |
ReentrantLock结合Condition使用示例:力扣1114
public class P1114_PrintInOrder{
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//测试代码
Foo foo = Foo.class.newInstance();
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.execute(() -> {
try {
foo.third(() -> System.out.println("first"));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.execute(() -> {
try {
foo.second(() -> System.out.println("second"));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.execute(() -> {
try {
foo.first(() -> System.out.println("third"));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.shutdown();
}
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Foo {
ReentrantLock lock = new ReentrantLock(false);
Condition condition = lock.newCondition();
Integer state = 3;
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
lock.lock();
while (state != 3) {
condition.await();
}
state = 2;
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
condition.signalAll();
lock.unlock();
}
public void second(Runnable printSecond) throws InterruptedException {
lock.lock();
while (state != 2) {
condition.await();
}
state = 1;
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
condition.signalAll();
lock.unlock();
}
public void third(Runnable printThird) throws InterruptedException {
lock.lock();
while (state != 1) {
condition.await();
}
state = 3;
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
condition.signalAll();
lock.unlock();
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
synchronized锁
synchronized关键字结合wait和notify的使用示例
public class Synchronize {
/**
* wait/notify方法的调用必须在该对象的锁(Monitor)中,否则抛出IllegalMonitorStateException异常
* notify方法调用之后只有等待代码退出synchronized块后,其他线程才可以获取到锁
*/
private final Object lock = new Object();
private boolean envReady = false;
public static void main(String[] args) {
Synchronize sync = new Synchronize();
sync.startWork();
sync.prepareEnv();
}
public void startWork() {
new WorkerThread().start();
}
public void prepareEnv() {
new PrepareEnvThread().start();
}
private class WorkerThread extends Thread {
public void run() {
System.out.println("线程 WorkThread 等待获取锁");
synchronized (lock) {
try {
System.out.println("线程 WorkThread 获取到锁");
if (!envReady) {
System.out.println("线程 WorkThread 放弃锁,wait");
lock.wait();
}
System.out.println("线程 WorkThread 收到通知后继续执行");
} catch (InterruptedException e) {
}
}
}
}
private class PrepareEnvThread extends Thread {
public void run() {
System.out.println("线程 PrepareEnvThread 等待获取锁");
synchronized (lock) {
System.out.println("线程 PrepareEnvThread 获取到锁");
envReady = true;
lock.notify();
System.out.println("通知 WorkThread");
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能