ReentrantLock类与Condition类配合实现等待/通知机制

一.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实现通知。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值