ReentrantLock的Condition选择性通知
2019-05-28 本文已影响0人
勇往直前z
今天浏览了并发同步的相关知识,使用ReentrantLock写了个小demo,主要关于选择性通知,在此记录一下。
1.介绍
ReentrantLock与synchronized 都是可重入锁、独占锁,ReentrantLock基于AQS,AQS基于CAS。
2.高级功能
①等待可中断
ReentrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
②可实现公平锁
即先到先得,通过构造函数ReentrantLock(boolean fair)制定。
③可实现选择性通知(锁可以绑定多个条件)
需要借助于Condition接口与newCondition() 方法,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。
3.选择性通知实现
用简单的代码写了机器人给老板洗澡的过程。以下:
①机器人服务
package com.example.demo.practice;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class RobotService {
private Lock lock = new ReentrantLock(true);
public Condition washCondition = lock.newCondition();
public void awaitCuoZao() {
lock.lock();
System.out.println("等着给老板搓澡...");
System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
try {
washCondition.await();
System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println("搓澡完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitMuyulu() {
lock.lock();
System.out.println("等着给老板打沐浴露...");
System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
try {
washCondition.await();
System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println("打沐浴露完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitChuanyi() {
lock.lock();
System.out.println("等着给老板更衣...");
System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
try {
washCondition.await();
System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println("更衣完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalWash() {
lock.lock();
System.out.println("老板:给我洗澡");
System.out.println("通知时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
try {
washCondition.signalAll();
} finally {
lock.unlock();
}
}
}
②线程类
package com.example.demo.practice;
public class WashThreadA implements Runnable {
private RobotService robotService;
public WashThreadA(RobotService robotService) {
this.robotService = robotService;
}
@Override
public void run() {
robotService.awaitCuoZao();
}
}
package com.example.demo.practice;
public class WashThreadB implements Runnable {
private RobotService robotService;
public WashThreadB(RobotService robotService) {
this.robotService = robotService;
}
@Override
public void run() {
robotService.awaitMuyulu();
}
}
package com.example.demo.practice;
public class WashThreadC implements Runnable {
private RobotService robotService;
public WashThreadC(RobotService robotService) {
this.robotService = robotService;
}
@Override
public void run() {
robotService.awaitChuanyi();
}
}
③测试类
package com.example.demo.practice;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReenTrantLockTest {
public static void main(String[] args) throws InterruptedException {
RobotService robotService = new RobotService();
System.out.println("老板:我想洗澡,去准备一下。");
WashThreadA washThreadA = new WashThreadA(robotService);
Thread czReady = new Thread(washThreadA);
czReady.setName("czReady");
czReady.start();
Thread.sleep(500);
WashThreadB washThreadB = new WashThreadB(robotService);
Thread myReady = new Thread(washThreadB);
myReady.setName("myReady");
myReady.start();
Thread.sleep(500);
WashThreadC washThreadC = new WashThreadC(robotService);
Thread gyReady = new Thread(washThreadC);
gyReady.setName("gyReady");
gyReady.start();
Thread.sleep(2000);
robotService.signalWash();
}
}
④控制台打印
老板:我想洗澡,去准备一下。
等着给老板搓澡...
开始等待时间:1559033214928 -- 当前线程:czReady
等着给老板打沐浴露...
开始等待时间:1559033215425 -- 当前线程:myReady
等着给老板更衣...
开始等待时间:1559033215926 -- 当前线程:gyReady
老板:给我洗澡
通知时间:1559033217926 -- 当前线程:main
结束等待时间:1559033217926 -- 当前线程:czReady
搓澡完毕!
结束等待时间:1559033220928 -- 当前线程:myReady
打沐浴露完毕!
结束等待时间:1559033223928 -- 当前线程:gyReady
更衣完毕!