• Lock接口之Condition接口


    之前在写显示锁的是后,在显示锁的接口中,提到了new Condition这个方法,这个方法会返回一个Condition对象

    简单介绍一下

    Condition接口:

      任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与synchronized同步关键字配合,可以实现等待/通知模式。之前写过一篇线程之间的协作(等待通知模式)是使用Object的wait和notify/notifyAll+Synchronized写的

      换而言之,synchronized关键字想要实现等待/通知模式,需要调用以上的四种方法。

      然后我们的Condition接口也提供了能够实现等待/通知模式,是与Lock配合实现的。

      我感觉这个Condition和那个差不多,也是用来完成线程之间的协作的

      但是二者在使用方式上以及功能特性上还是有所差别的。

    Object对比Condition:

     由此表可以看出,condition接口可以有多个等待队列,而object监视器方法只有一个队列,而且还不支持在等待状态响应中断,还不支持当前线程释放锁并进入等待状态到将来的某个时间。

    示例:

      也不打算写新的示例了,用这个Condition接口改造一下之前使用等待通知模式的那个案例吧

      Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到Condition对象关联的锁。Condition对象是由Lock对象(调用Lock对象的newCondition()方法)创建出来的。其实就是,Condition是依赖Lock对象的。就像使用wait/notify需要依赖Synchronized锁一样,Condition的使用方式比较简单,需要注意在调用方法前获取锁

    创建等待通知类

    package org.dance.day4.condition;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 类说明:使用Condition接口实现等待通知模式
     */
    public class ExpressCond {
    
        public final static String CITY = "ShangHai";
    
        /**
         * 快递运输里程数
         */
        private int km;
    
        /**
         * 快递到达地点
         */
        private String site;
    
        /**
         * 创建显示锁
         */
        private final Lock lock = new ReentrantLock();
    
        /**
         * 检测城市变化
         */
        private final Condition siteCond = lock.newCondition();
    
        /**
         * 检测公里数变化
         */
        private final Condition kmCond = lock.newCondition();
    
        public ExpressCond() {
        }
    
        public ExpressCond(int km, String site) {
            this.km = km;
            this.site = site;
        }
    
        /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
        public void changeKm() {
            // 获取锁
            lock.lock();
            try {
                this.km = 101;
                // 唤醒在kmCond 上 等待的线程
                kmCond.signal();
            } finally {
                lock.unlock();
            }
        }
    
        /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
        public void changeSite() {
            // 获取锁
            lock.lock();
            try {
                this.site = "BeiJing";
                // 唤醒在siteCond 上 等待的线程
                siteCond.signal();
            } finally {
                lock.unlock();
            }
        }
    
        /*当快递的里程数大于100时更新数据库*/
        public void waitKm() {
            lock.lock();
            try {
                while (this.km <= 100) {
                    try {
                        kmCond.await();
                    } catch (InterruptedException e) {
                        // 处理线程中断
                        Thread.currentThread().interrupt();
                        e.printStackTrace();
                    }
                    System.out.println("check km thread[" + Thread.currentThread().getId()
                            + "] is be notifed.");
                }
            } finally {
                lock.unlock();
            }
            System.out.println("the Km is " + this.km + ",I will change db");
        }
    
        /*当快递到达目的地时通知用户*/
        public void waitSite() {
            lock.lock();
            try {
                while (CITY.equals(this.site)) {
                    try {
                        siteCond.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("check site thread[" + Thread.currentThread().getId()
                            + "] is be notifed.");
                }
            } finally {
                lock.unlock();
            }
            System.out.println("the site is " + this.site + ",I will call user");
        }
    }

    通过代码可以看见,我们一个锁,是可以携带多个等待队列的

    创建测试类

    package org.dance.day4.condition;
    
    /**
     *类说明:测试Lock和Condition实现等待通知
     */
    public class TestCond {
        private static ExpressCond express = new ExpressCond(0,ExpressCond.CITY);
    
        /*检查里程数变化的线程,不满足条件,线程一直等待*/
        private static class CheckKm extends Thread{
            @Override
            public void run() {
                express.waitKm();
            }
        }
    
        /*检查地点变化的线程,不满足条件,线程一直等待*/
        private static class CheckSite extends Thread{
            @Override
            public void run() {
                express.waitSite();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            for(int i=0;i<3;i++){
                new CheckSite().start();
            }
            for(int i=0;i<3;i++){
                new CheckKm().start();
            }
    
            Thread.sleep(1000);
            express.changeKm();//快递里程变化
        }
    }

    执行结果:

    check km thread[14] is be notifed.
    the Km is 101,I will change db

    通过执行结果,我们可以清晰的看到,他是直接唤醒了,在公里数变化上等待的线程的,在之前的等待通知模式中,也就是wait/notify/notifyAll+Sync实现的等待通知模式中,推荐大家使用notifyAll()来唤醒正在等待中的线程,但是在使用Condition接口中,推荐大家使用signal,而不是signalAll().为啥呢?因为wait/notify/notifyAll是Object的方法,在指定的对象中等待的可能是多个线程,分别在检测不同的变量,可能造成信号的拦截,所以推荐使用全部唤醒,,但是在使用Condition上却不是,因为他是多个等待队列,他清晰的知道自己应该唤醒那个线程,所以推荐使用signal,至于Condition的实现分析暂时先不写,等写完AQS再写方便,大家理解,我感觉不是所有相关的知识都要堆在一起,要是理解不了,再深入也没用

    作者:彼岸舞

    时间:2020114

    内容关于:并发编程

    本文来源于网络,只做技术分享,一概不负任何责任

  • 相关阅读:
    QT POST/GET HTTP操作
    PHP生成json
    Windows 获取进程ID
    易语言 多个窗口
    易语言 内存修改框架
    易语言 MD5生成
    易语言 获取验证码
    易语言网页登录 POST
    cs1.6 8倍镜
    HTMLTestRunner.py(Python3)
  • 原文地址:https://www.cnblogs.com/flower-dance/p/13923528.html
Copyright © 2020-2023  润新知