Java并发编程(06):Lock机制下API用法详解
2021-04-26 13:29
标签:key 简介 ofo 性能 商品 点餐 tor except info Lock加锁相关结构中涉及两个使用广泛的基础API:ReentrantLock类和Condition接口,基本关系如下: Lock接口 Java并发编程中资源加锁的根接口之一,规定了资源锁使用的几个基础方法。 ReentrantLock类 实现Lock接口的可重入锁,即线程如果获得当前实例的锁,并进入任务方法,在线程没有释放锁的状态下,可以再次进入任务方法,特点:互斥排它性,即同一个时刻只有一个线程进入任务。 Condition接口 Condition接口描述可能会与锁有关联的条件变量,提供了更强大的功能,例如在线程的等待/通知机制上,Conditon可以实现多路通知和选择性通知。 生产消费模式 写线程向容器中添加数据,读线程从容器获取数据,如果容器为空时,读线程等待。 这个生产消费模式和生活中的点餐场景极为类似,用户下单,通知后厨烹饪,烹饪完成之后通知送餐。 顺序执行模式 既然线程执行可以互相通知,那也可以基于该机制实现线程的顺序执行,基本思路:在一个线程执行完毕后,基于条件唤醒下个线程。 该案例经常出现在多线程的面试题中,如何实现ABC的顺序打印问题,基本思路就是基于线程的等待通知机制,但是实现方式很多,上述只是其中一种方式。 重入锁的排它特性决定了性能会产生瓶颈,为了提升性能问题,JDK中还有另一套读写锁机制。读写锁中维护一个共享读锁和一个排它写锁,在实际开发中,读的场景还是偏多的,所以读写锁可以很好的提高并发性。 读写锁相关结构中两个基础API:ReadWriteLock接口和ReentrantReadWriteLock实现类,基本关系如下: ReadWriteLock 提供两个基础方法,readLock获取读机制锁,writeLock获取写机制锁。 ReentrantReadWriteLock 接口ReadWriteLock的具体实现,特点:基于读锁时,其他线程可以进行读操作,基于写锁时,其他线程读、写操作都禁止。 读写分离模式 通过读写锁机制,分别向数据容器Map中写入数据和读取数据,以此验证读写锁机制。 说明:当put方法一直在睡眠状态时,因为写锁的排它性质,所以读方法是无法执行的。 LockSupport简介 LockSupprot定义一组公共静态方法,这些方法提供最基本的线程阻塞和唤醒功 基础方法 park():当前线程阻塞,当前线程被中断或调用unpark方法,park()方法中返回; park(Object blocker):功能同park(),传入Object对象,记录导致线程阻塞的阻塞对象,方便问题排查; parkNanos(long nanos):指定时间nanos内阻塞当前线程,超时返回; unpark(Thread thread):唤醒指定处于阻塞状态的线程; 代码案例 该流程在购物APP上非常常见,当你准备支付时放弃,会有一个支付失效,在支付失效期内可以随时回来支付,过期后需要重新选取支付商品。 这里基于LockSupport中park和unpark控制线程状态,实现的等待通知机制。 推荐文章:并发编程系列 Java并发编程(06):Lock机制下API用法详解 标签:key 简介 ofo 性能 商品 点餐 tor except info 原文地址:https://blog.51cto.com/14439672/2508773一、Lock体系结构
1、基础接口简介
2、使用案例
public class LockAPI01 {
private static Lock lock = new ReentrantLock() ;
private static Condition condition1 = lock.newCondition() ;
private static Condition condition2 = lock.newCondition() ;
public static void main(String[] args) throws Exception {
List
public class LockAPI02 {
public static void main(String[] args) {
PrintInfo printInfo = new PrintInfo() ;
ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new PrintA(printInfo));
service.execute(new PrintB(printInfo));
service.execute(new PrintC(printInfo));
}
}
class PrintA implements Runnable {
private PrintInfo printInfo ;
public PrintA (PrintInfo printInfo){
this.printInfo = printInfo ;
}
@Override
public void run() {
printInfo.printA ();
}
}
class PrintB implements Runnable {
private PrintInfo printInfo ;
public PrintB (PrintInfo printInfo){
this.printInfo = printInfo ;
}
@Override
public void run() {
printInfo.printB ();
}
}
class PrintC implements Runnable {
private PrintInfo printInfo ;
public PrintC (PrintInfo printInfo){
this.printInfo = printInfo ;
}
@Override
public void run() {
printInfo.printC ();
}
}
class PrintInfo {
// 控制下个执行的线程
private String info = "A";
private ReentrantLock lock = new ReentrantLock();
// 三个线程,三个控制条件
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
public void printA (){
try {
lock.lock();
while (!info.equals("A")) {
conditionA.await();
}
System.out.print("A");
info = "B";
conditionB.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB (){
try {
lock.lock();
while (!info.equals("B")) {
conditionB.await();
}
System.out.print("B");
info = "C";
conditionC.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC (){
try {
lock.lock();
while (!info.equals("C")) {
conditionC.await();
}
System.out.print("C");
info = "A";
conditionA.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
二、读写锁机制
1、基础API简介
2、使用案例
public class LockAPI03 {
public static void main(String[] args) throws Exception {
DataMap dataMap = new DataMap() ;
Thread read = new Thread(new GetRun(dataMap)) ;
Thread write = new Thread(new PutRun(dataMap)) ;
write.start();
Thread.sleep(2000);
read.start();
}
}
class GetRun implements Runnable {
private DataMap dataMap ;
public GetRun (DataMap dataMap){
this.dataMap = dataMap ;
}
@Override
public void run() {
System.out.println("GetRun:"+dataMap.get("myKey"));
}
}
class PutRun implements Runnable {
private DataMap dataMap ;
public PutRun (DataMap dataMap){
this.dataMap = dataMap ;
}
@Override
public void run() {
dataMap.put("myKey","myValue");
}
}
class DataMap {
Map
三、基础工具类
能。public class LockAPI04 {
public static void main(String[] args) throws Exception {
OrderPay orderPay = new OrderPay("UnPaid") ;
Thread orderThread = new Thread(orderPay) ;
orderThread.start();
Thread.sleep(3000);
orderPay.changeState("Pay");
LockSupport.unpark(orderThread);
}
}
class OrderPay implements Runnable {
// 支付状态
private String orderState ;
public OrderPay (String orderState){
this.orderState = orderState ;
}
public synchronized void changeState (String orderState){
this.orderState = orderState ;
}
@Override
public void run() {
if (orderState.equals("UnPaid")){
System.out.println("订单待支付..."+orderState);
LockSupport.park(orderState);
}
System.out.println("orderState="+orderState);
System.out.println("订单准备发货...");
}
}
四、源代码地址
GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent
序号
文章标题
01
Java并发:线程的创建方式,状态周期管理
02
Java并发:线程核心机制,基础概念扩展
03
Java并发:多线程并发访问,同步控制
04
Java并发:线程间通信,等待/通知机制
05
Java并发:悲观锁和乐观锁机制
下一篇:C++ 引用作为函数的返回值