文档章节

(七)java多线程之Condition

天之妖星
 天之妖星
发布于 2017/05/08 14:24
字数 2600
阅读 1
收藏 0

本人邮箱: kco1989@qq.com
欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代码已经全部托管github有需要的同学自行下载

引言

在写(五)java多线程之Lock类时,我们暂时忽略掉Lock的一个方法,那就是Lock.newCondition(),这个方法返回一个Condition,现在我们这章就重点讲这个东东是什么,以及怎么使用.

理论

Condition的中文翻译是状态.没错,这个就是让多线程在不同状态切换其他线程执行.跟Object.waitObject.notify有点类似.

  • Condition.await: 让当前线程一直等到直到获取信号,或者发生中断.通过和lock锁互相配合,会使当前线程一直睡眠直到一下四种情况的其中一种发生:
    • 另外一个线程调用当前Conditionsignal方法,这当前线程会被挑选出来,并被唤醒
    • 其他线程调用了当前ConditionsignalAll方法
    • 其他线程调用了当前线程的中断,这当前中断会被挂起
    • 当前线程被假唤醒
  • Condition.awaitUninterruptiblyCondition.await类似,只是不能被中断
  • Condition.await(long time, TimeUnit unit) 当前线程会被唤醒,要么是获得信号,要么是中断,要么是指定时间到
  • Condition.awaitUntil(Date deadline)当前线程会被唤醒,要么是获得信号,要么是中断,要么是到了指定结束时间
    一般用法如下
    java
    >boolean aMethod(Date deadline) {
    > boolean stillWaiting = true;
    > lock.lock();
    > try {
    > while (!conditionBeingWaitedFor()) {
    > if (!stillWaiting)
    > return false;
    > stillWaiting = theCondition.awaitUntil(deadline);
    > }
    > // ...
    > } finally {
    > lock.unlock();
    > }
    >}
    >
  • Condition.signal 唤醒等待的线程.如果当前的condition有多个线程在等待的话,这会唤醒其中一,且这个线程在返回await前必须重新获得锁
  • ‘Condition.signalAll’ 唤醒所有等待的线程.如果当前的condition有多个线程在等待,则所有的线程都会被唤醒,且这些被唤醒的线程必须在返回await之前重新获得锁

例子1

枯燥无聊的理论,看完之后就忘记,还是要写一个例子加深印象吧.这里我们还是用之前`小明`和`小红`谈人生,谈理想的例子继续说明吧
  • 首先要中间人GrilProduct,花花公子PlayBoy和测试类TestMain,都是跟之前[(三)java多线程之wait notify notifyAll](../test3/(三)java多线程之wait notify notifyAll,md)一样,这里就不占用篇幅了

  • 我们继续改写卧室Room

public class Room {
    Lock lock = new ReentrantLock();
    Condition boyIsCome = lock.newCondition();
    Condition girlIsCome = lock.newCondition();
    private String gril = null;

    public void makeGridInRoom(String gril){
        lock.lock();
        try {
            while (this.gril != null){
                System.out.println(gril + " 我的心在等待... 永远在等待.. " );
                girlIsCome.await();
            }

            Thread.sleep(10);
            this.gril = gril;
            boyIsCome.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void playWithGril(String boy){
        lock.lock();
        try {
            while (this.gril == null){
                System.out.println(boy + " 我的心在等待... 永远在等待.. " );
                boyIsCome.await();
            }

            Thread.sleep(10);
            System.out.println(boy + " play with " + this.gril);
            Thread.sleep(500);
            this.gril = null;
            girlIsCome.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

运行一下,结果如下

小红1号 我的心在等待... 永远在等待.. 
小明0号 play with 小红0号
小明9号 我的心在等待... 永远在等待.. 
小明2号 我的心在等待... 永远在等待.. 
小明5号 我的心在等待... 永远在等待.. 
小明7号 我的心在等待... 永远在等待.. 
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红2号 我的心在等待... 永远在等待.. 
小明9号 play with 小红1号
小明2号 我的心在等待... 永远在等待.. 
小明5号 我的心在等待... 永远在等待.. 
小明7号 我的心在等待... 永远在等待.. 
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红3号 我的心在等待... 永远在等待.. 
小明2号 play with 小红2号
小明5号 我的心在等待... 永远在等待.. 
小明7号 我的心在等待... 永远在等待.. 
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红4号 我的心在等待... 永远在等待.. 
小明5号 play with 小红3号
小明7号 我的心在等待... 永远在等待.. 
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红5号 我的心在等待... 永远在等待.. 
小明7号 play with 小红4号
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红6号 我的心在等待... 永远在等待.. 
小明4号 play with 小红5号
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红7号 我的心在等待... 永远在等待.. 
小明6号 play with 小红6号
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红8号 我的心在等待... 永远在等待.. 
小明1号 play with 小红7号
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红9号 我的心在等待... 永远在等待.. 
小明3号 play with 小红8号
小明8号 我的心在等待... 永远在等待.. 
小明8号 play with 小红9

跟之前的结果差不多.

例子2

这时候就有人质疑了,既然结果跟用Object.waitObject.notify一样,那为什么要用这个呢?细心的读者可以发现了,每次运行,同一个小明可能和不同的小红谈人生和理想.这时候小明是很开心.但小红却不乐意,觉得小明太花心,太不专一,什么甜言蜜语都是骗人的.好,那我们现在就让小明专一.帮小红排除他们的烦恼.

这时候全部的类都要改造了,没办法小红太强势了

  • 首先我们改造一下中间人GrilProduct,让每一个小红都自带编号进入卧室等候
public class GrilProduct implements Runnable{

    private Room room;
    public GrilProduct(Room room) {
        this.room = room;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i ++){
            room.makeGridInRoom("小红" + i + "号", i);
        }
    }
}
  • 之后我们改造花花公子,他们进入房间时,要拿着小红对应的编号进入
public class PlayBoy implements Runnable{
    private Room room;
    private String boy;
    private int index;
    public PlayBoy(Room room, String boy, int index) {
        this.room = room;
        this.boy = boy;
        this.index = index;
    }

    @Override
    public void run() {
        room.playWithGril(boy, index);
    }
}
  • 之后就是要改写卧室类Room了 ,让小红小明的号码对应上,才让他们谈人生和理想,不然就让他们继续等待..
public class Room {
    Lock lock;
    List<Condition> boyIsCome;
    Condition girlIsCome;
    private String gril = null;
    private int index = -1;
    public Room(){
        lock = new ReentrantLock();
        girlIsCome = lock.newCondition();
        boyIsCome = new ArrayList<>();
        for (int i = 0; i < 10; i ++){
            boyIsCome.add(lock.newCondition());
        }
    }

    public void makeGridInRoom(String gril, int index){
        lock.lock();
        try {
            while (this.gril != null){
                System.out.println(gril + " 我的心在等待... 永远在等待.. " );
                girlIsCome.await();
            }

            Thread.sleep(10);
            this.gril = gril;
            this.index = index;
            boyIsCome.get(index).signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void playWithGril(String boy, int index){
        lock.lock();
        try {
            while (this.gril == null || this.index != index){
                System.out.println(boy + " 我的心在等待... 永远在等待.. " );
                boyIsCome.get(index).await();
            }
            Thread.sleep(10);
            System.out.println(boy + " play with " + this.gril);
            Thread.sleep(500);
            this.gril = null;
            this.index = -1;
            girlIsCome.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
  • 最后改写我们的测试类TestMain
public class TestMain {
    public static void main(String[] args) {
        Room room = new Room();
        Thread grilProduct = new Thread(new GrilProduct(room));
        Set<Thread> boyThread = new HashSet<>();
        for (int i = 0; i < 10; i ++){
            boyThread.add(new Thread(new PlayBoy(room, "小明" + i + "号", i)));
        }

        grilProduct.start();
        for (Thread boy : boyThread){
            boy.start();
        }
    }
}

运行一下,结果如下:

小红1号 我的心在等待... 永远在等待.. 
小明9号 我的心在等待... 永远在等待.. 
小明0号 play with 小红0号
小明2号 我的心在等待... 永远在等待.. 
小明5号 我的心在等待... 永远在等待.. 
小明7号 我的心在等待... 永远在等待.. 
小明4号 我的心在等待... 永远在等待.. 
小明6号 我的心在等待... 永远在等待.. 
小明1号 我的心在等待... 永远在等待.. 
小明3号 我的心在等待... 永远在等待.. 
小明8号 我的心在等待... 永远在等待.. 
小红2号 我的心在等待... 永远在等待.. 
小明1号 play with 小红1号
小红3号 我的心在等待... 永远在等待.. 
小明2号 play with 小红2号
小红4号 我的心在等待... 永远在等待.. 
小明3号 play with 小红3号
小红5号 我的心在等待... 永远在等待.. 
小明4号 play with 小红4号
小红6号 我的心在等待... 永远在等待.. 
小明5号 play with 小红5号
小红7号 我的心在等待... 永远在等待.. 
小明6号 play with 小红6号
小红8号 我的心在等待... 永远在等待.. 
小明7号 play with 小红7号
小红9号 我的心在等待... 永远在等待.. 
小明8号 play with 小红8号
小明9号 play with 小红9

小明小红终于配对了,妈妈再也不用我被小红们追着打了,不过,小明们,我就对不住你们了.~~~~~~


打赏

如果觉得我的文章写的还过得去的话,有钱就捧个钱场,没钱给我捧个人场(帮我点赞或推荐一下)
微信打赏支付宝打赏

© 著作权归作者所有

天之妖星
粉丝 1
博文 30
码字总数 58258
作品 0
深圳
高级程序员
私信 提问
Java 并发编程源码解析汇总篇

java并发编程,内存模型 java并发编程,volatile内存实现和原理 Java并发编程,并发基础 Java 并发编程,线程池(ThreadPoolExecutor)源码解析 Java并发编程,Executor 框架介绍 Java并发编...

郑加威
2018/12/23
0
0
JAVA多线程-基础Synchronized

后篇: JAVA多线程-基础Lock Condition 并发集合 JAVA多线程-交互计算 Future Callable Promise 读懂代码,首先要懂得thread的几个状态,以及它们之间的转换. Java thread的状态有new, runnable...

xpbug
2012/11/07
0
10
Java程序员进化为架构师需要掌握的知识

Java程序员进化为架构师掌握的知识: 一:Java知识 1、进制转换 2、Java基本数据类型 面向对象相关知识 3、类、接口、抽象类 this关键字、static关键字、final关键字 方法的参数传递机制 Ja...

andogo
2014/05/16
1K
2
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
0
0
JAS 2.5.4821 发布,Java 代数系统

Java Algebra System 2.5.4821 发布,此版本更新内容如下: brings the solvable polynomial common divisor package edu.jas.fd in a partially usable condition The definition of great......

oschina
2014/04/24
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

微信小程序和百度小程序开发的一些不同点

1: initActive从onload放到onready中 2: bindtap='{{childTickeData.freeadd?"childticket":""}}',语法错误。会导致页面加载不出来,而且也不报任何错。 3:使用搬家工具,支付api名称转换......

醉雨
6分钟前
0
0
最近执行过的SQL语句查询

SELECT TOP 1000 ST.text AS '执行的SQL语句' , QS.execution_count AS '执行次数' , QS.total_elapsed_time / 10000 AS '耗时' , QS.total_logical_reads AS '逻辑读取次数' , QS.total_lo......

神手--追魂
7分钟前
0
0
从濒临解散到浴火重生,OceanBase 这十年经历了什么?

阿里妹导读:谈及国产自研数据库,就不得不提 OceanBase。与很多人想象不同的是,OceanBase 并非衔着金钥匙出生的宠儿。相反,它曾无人看好、困难重重,整个团队甚至数度濒临解散。 从危在旦...

阿里云官方博客
10分钟前
0
0
阿里开发者招聘节 | 面试题02-04:给定一个二叉搜索树(BST),找到树中第K小的节点

为帮助开发者们提升面试技能、有机会入职阿里,云栖社区特别制作了这个专辑——阿里巴巴资深技术专家们结合多年的工作、面试经验总结提炼而成的面试真题这一次将陆续放出(面试题官方参考答案...

阿里云云栖社区
27分钟前
1
0
使用Redis SETNX 命令实现分布式锁

基于setnx和getset http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法。 SETNX命令简介 命令格式 SETNX key value 将 ke...

彬彬公子
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部