admin管理员组文章数量:1599753
一.ReentrantLock概述:
ReentrantLock和synchronized一样效果,都可以同步执行,ReentrantLock通过lock方法获得锁,unlock方法释放锁。
二.ReentrantLock常用方法:
lock(): 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回,否则阻塞。
lockInterruptibly():如果当前线程未被中断,获取锁。
tryLock():尝试获得锁,仅在调用时锁未被线程占用,获得锁。
tryLock(long timeout TimeUnit unit):如果锁在给定等待时间内没有被另一个线程保持,则获取该锁。
unlock():释放锁。
getQueueLength():返回正等待获取此锁的线程估计数,比如启动10个线程,1个线程获得锁,此时返回的是9。
getWaitQueueLength(Condition condition):返回等待与此锁相关的给定条件的线程估计数。比如10个线程,用同一个
condition对象,并且此时这10个线程都执行了condition对象的await方法,那么此时执行此方法返回10。
hasWaiters(Condition condition):查询是否有线程等待与此锁有关的给定条件(condition),对于指定contidion对象,有多少线程执行了condition.await方法。
hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁。
hasQueuedThreads():是否有线程等待此锁。
isFair():该锁是否公平锁。
isHeldByCurrentThread():当前线程是否保持锁锁定,线程的执行lock方法的前后分别是false和true。
isLock():此锁是否有任意线程占用。
三.ReentrantLock类与Condition类配合实现等待/通知机制:
关键字synchronized与wait()合notify()或notifyAll()结合可以实现等待/通知机制。而ReentrantLock和Condition配合
也可以实现等待/通知机制。使用notify()和notifyAll()无法选择性的通知线程。使用Condition的优点就是可以在Lock
对象里面创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition中,从而实现有选择性地进行
线程通知,使线程调度更加的灵活。
Condition类方法:
await():使线程等待相当于Object对象中的wait()方法。
await(long time, TimeUnit unit):相当于Object对象中的wait(long timeout)方法。
signal():通知单个线程相当于Object对象中的notify()方法。
signalAll():通知所有线程相当于Object对象中的notifyAll()方法。
四.通过ReentrantLock和Condition配合实现单个线程的等待和通知:
1.定义一个类,并且实现对应的等待和唤醒方法:
public class MyService {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* 等待
*/
public void await(){
try{
lock.lock();
System.out.println("await time: "+System.currentTimeMillis());
condition.await(); //使线程处于等待
}catch (Exception e){ //线程中断
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* 唤醒
*/
public void signal(){
try{
lock.lock();
System.out.println("signal time: "+System.currentTimeMillis());
condition.signal(); //唤醒线程
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
2.定义一个线程的实现类,并且以构造注入的方式,注入上面创建的方法类,并在覆盖的run方法中调用等待方法.
public class MyThread extends Thread{
private MyService myService;
public MyThread(MyService myService) {
super();
this.myService = myService;
}
@Override
public void run() {
myService.await();
}
}
3.创建测试类,线程调用start()之后虽然是启动了,但是在run方法中调用await()时进行了等待,因为需要进行唤醒
public class TestCondition {
public static void main(String[] args) {
try{
MyService myService = new MyService();
MyThread myThread = new MyThread(myService);
/**
* 线程启动之后调用run方法,然后执行方法中的await方法使线程处于等待状态
*/
myThread.start();
/**
* 使当前主线程睡眠,晚点执行
*/
Thread.sleep(5000);
/**
* 调用signal方法,通知MyService中的Condition(监听器)中注册的线程
* 进行唤醒执行
*/
myService.signal();
}catch (Exception e){
e.printStackTrace();
}
}
}
4.测试结果:
五.通过ReentrantLock和Condition配合实现多个指定线程的等待和通知:
1.还是创建一个方法类,但是要创建多个Condition对象,因为这是区别线程的关键,只有区分了,才能进行指定不同线程之间的唤醒操作.
对应的不同的Condition要有自己的等待和唤醒方法:
public class MyService {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
/**
* A 等待
*/
public void awaitA(){
try{
lock.lock();
System.out.println("waitA begin time: "+System.currentTimeMillis());
conditionA.await(); //等待
System.out.println("waitA end time: "+System.currentTimeMillis());
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* B 等待
*/
public void awaitB(){
try{
lock.lock();
System.out.println("waitB begin time: "+System.currentTimeMillis());
conditionB.await(); //等待
System.out.println("waitB end time: "+System.currentTimeMillis());
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* conditionA通知:
* signal() 通知单个线程
* signalAll() 通知多个线程
*/
public void signalAll_A(){
try{
lock.lock();
System.out.println("signalAll_A begin time: "+System.currentTimeMillis()
+ ", ThreadName = "+Thread.currentThread().getName());
//
conditionA.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* conditionB通知:
* signal() 通知单个线程
* signalAll() 通知所有线程
*/
public void signalAll_B() {
try {
lock.lock();
System.out.println("signalAll_B begin time: " + System.currentTimeMillis()
+ ", ThreadName = " + Thread.currentThread().getName());
// 通知conditionB监视器中所有处于等待的线程进行唤醒
conditionB.signalAll();
} catch (IllegalMonitorStateException ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
}
2.分别创建两个线程的实现类,分别调用两个Condition的await(),使线程处于等待状态:
线程A:
public class MyThreadA extends Thread{
private MyService myService;
public MyThreadA(MyService myService) {
super();
this.myService = myService;
}
@Override
public void run() {
myService.awaitA();
}
}
线程B:
public class MyThreadB extends Thread{
private MyService myService;
public MyThreadB(MyService myService) {
super();
this.myService = myService;
}
@Override
public void run() {
myService.awaitB();
}
}
3.测试:
public class RunTest {
public static void main(String[] args) {
try{
MyService myService = new MyService();
MyThreadA threadA = new MyThreadA(myService);
threadA.setName("AAAAA");
threadA.start();
MyThreadB threadB = new MyThreadB(myService);
threadB.setName("BBBBB");
threadB.start();
//main线程休眠5秒,才执行后面的代码
Thread.sleep(5000);
/**
* 线程休眠5秒后开始执行service.signalAll_A(),
* 单纯就是唤醒ThreadA线程,不唤醒ThreadB线程,
* 这么测试的目的,就是想验证Condition能否做到只唤醒部分线程
*/
myService.signalAll_A();
myService.signalAll_B();
}catch (Exception e){
e.printStackTrace();
}
}
}
4.测试结果:
六.总结:
1)ReentrantLock能实现Synchronized一样的同步效果,通过lock()上锁,unlock()解锁。
2)ReentrantLock依赖特殊的cpu指令,手动加锁和解锁实现同步效果。
3)ReentrantLock的Condition可以实现等待/通知模式(生产/消费者模型),线程注册到Condition,
通过await方法等待,通过signal或signalAll实现通知。
本文标签: 机制通知ReentrantLockcondition
版权声明:本文标题:ReentrantLock类与Condition类配合实现等待通知机制 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1728322729a1154037.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论