三.ReetrantLock选择性通知与公平锁,及部分特性与synchronized的比较
一.写在开头
通过一个西游记里头经典的桥段,太上老君炼丹,初步介绍ReetrantLock的选择性通知,ReetrantLock公平锁/非公平锁。希望能够帮助到点进来的你。配合跑代码看结果效果更佳。
二.太上老君炼丹的故事
书接上回,太上老君者,大道之主宰...(此处省略一万字)...玉皇大帝祭出了斩妖刀,也无法将老孙灭杀。太上老君站了出来,请玉帝将老孙交付于他,只要他将老孙放进炼丹炉用三昧真火烧炼,即可灭杀老孙。此时,太上老君带着他的三个徒弟来到了炼丹洞府:都率宫!
(正片开始!)太上老君有三个徒弟A,B,C,辅助他炼化妖猴。
| 徒弟A | 徒弟B | 徒弟C | |
| 职责 | 负责开炉 | 负责把悟空扔进炼丹炉 | 负责封炉 |
炼化流程:徒弟们先各自准备,准备好后,太上老君一声令下。徒弟A开炉-->徒弟B把悟空扔进炼丹炉-->徒弟C封炉,分工明确
Demo中,太上老君为test主线程,启动三个徒弟线程ABC,线程A B C先等待,等主线程signalAll()唤醒所有等待线程。
运行截图:


三.ReetrantLock选择性通知与公平锁,及部分特性与synchronized的比较
ReentrantLock与synchronized 都是可重入锁、独占锁,ReentrantLock基于AQS,AQS基于CAS。
ReetrantLock的特性:
1.等待可中断
ReentrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
相比synchronized,synchronized不可中断。
2.可实现公平锁
注意,new ReentrantLock()默认情况下,使用非公平锁。本例采用了公平锁new ReentrantLock(true),保证线程获取锁的顺序。
简述一下公平锁和非公平锁:
公平锁:先进来的线程先执行。
非公平锁:后进来的线程也可能先执行。
相比synchronized,synchronized只能是非公平锁。
3.可实现选择性通知(锁可以绑定多个条件)
需要借助于Condition接口与newCondition() 方法,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。
四.例子代码
package ReetrantLockTest;
public class ReenTrantLockTest {
public static void main(String[] args) throws InterruptedException {
OrderService orderService = new OrderService();
System.err.println("太上老君:今日老夫终于擒获此妖猴!为天庭除害!徒儿们现在去准备开炉事宜,让老夫炼了这厮!");
PupilThreadA pupilThreadA = new PupilThreadA(orderService);
Thread pupilA = new Thread(pupilThreadA);
pupilA.setName("徒弟A(负责开炉)");
pupilA.start();
Thread.sleep(500);
PupilThreadB pupilThreadB = new PupilThreadB(orderService);
Thread pupilB = new Thread(pupilThreadB);
pupilB.setName("徒弟B(负责把悟空扔进炼丹炉)");
pupilB.start();
Thread.sleep(500);
PupilThreadC pupilThreadC = new PupilThreadC(orderService);
Thread pupilC = new Thread(pupilThreadC);
pupilC.setName("徒弟C(持有太上老君的法器)");
pupilC.start();
Thread.sleep(2000);
orderService.signalAll();
Thread.sleep(500);
System.err.println("太上老君:干的漂亮!!");
}
}
package ReetrantLockTest;
public class PupilThreadA implements Runnable {
private OrderService orderService;
public PupilThreadA(OrderService robotService) {
this.orderService = robotService;
}
@Override
public void run() {
orderService.awaitOpen();
}
}
package ReetrantLockTest;
public class PupilThreadB implements Runnable {
private OrderService orderService;
public PupilThreadB(OrderService robotService) {
this.orderService = robotService;
}
@Override
public void run() {
orderService.awaitThrow();
}
}
package ReetrantLockTest;
public class PupilThreadC implements Runnable {
private OrderService orderService;
public PupilThreadC(OrderService robotService) {
this.orderService = robotService;
}
@Override
public void run() {
orderService.awaitWeapon();
}
}
package ReetrantLockTest;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class OrderService {
private Lock lock = new ReentrantLock(true);
public Condition orderCondition = lock.newCondition();
public void awaitOpen() {
lock.lock();
System.out.println("");
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟A开始画解封炼丹炉的符咒...");
System.out.println("徒弟A画完了符咒-开始等待老君下命令(await()开始等待)");
System.out.println("");
try {
orderCondition.await();
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟A接到老君命令-结束等待-开始用符咒解封炼丹炉");
System.out.println("炼丹炉解封完毕!");
System.out.println("");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitThrow() {
lock.lock();
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟B开始做广播体操热身...");
System.out.println("徒弟B热身完毕-开始等待老君下命令(await()开始等待) ");
System.out.println("");
try {
orderCondition.await();
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟B接到老君命令-结束等待-用天生神力把悟空扔进炼丹炉 ");
System.out.println("妖猴入炉完毕!");
System.out.println("");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitWeapon() {
lock.lock();
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟C开始屁颠屁颠跑去拿太上老君的法器...");
System.out.println("徒弟C准备好了法器-开始等待老君下命令(await()开始等待) ");
try {
orderCondition.await();
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.out.println("徒弟C-结束等待-开始用老君法器封印炼丹炉");
System.out.println("封炉完毕!");
System.out.println("");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAll() {
lock.lock();
System.out.println("");
System.out.println("----当前线程:" + Thread.currentThread().getName());
System.err.println("太上老君:徒儿们,都准备好了吧?!干活!!!(signalAll()唤醒所有的等待线程)");
System.out.println("");
try {
orderCondition.signalAll();
} finally {
lock.unlock();
}
}
}
都看到这里了,点个赞再走呗~你有酒吗?我有故事。
本文通过西游记中太上老君炼丹的故事,阐述了ReentrantLock的选择性通知和公平锁概念。文章详细比较了ReentrantLock与synchronized的差异,包括等待可中断、公平锁实现以及选择性通知,并通过代码示例进行解释。
1236

被折叠的 条评论
为什么被折叠?



