接近一周没更新《Java线程》专栏了,主要是这周工作上比较忙,生活上也比较忙,呵呵,进入正题,上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇之上,使用Lock如何处理线程通信。

那么引入本篇的主角,Condition,Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。下面将之前写过的一个线程通信的例子替换成用Condition实现(Java线程(三)),代码如下:

  1. public class ThreadTest2 {
  2. public static void main(String[] args) {
  3. final Business business = new Business();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. threadExecute(business, "sub");
  8. }
  9. }).start();
  10. threadExecute(business, "main");
  11. }
  12. public static void threadExecute(Business business, String threadType) {
  13. for(int i = 0; i < 100; i++) {
  14. try {
  15. if("main".equals(threadType)) {
  16. business.main(i);
  17. } else {
  18. business.sub(i);
  19. }
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. }
  26. class Business {
  27. private boolean bool = true;
  28. private Lock lock = new ReentrantLock();
  29. private Condition condition = lock.newCondition();
  30. public /*synchronized*/ void main(int loop) throws InterruptedException {
  31. lock.lock();
  32. try {
  33. while(bool) {
  34. condition.await();//this.wait();
  35. }
  36. for(int i = 0; i < 100; i++) {
  37. System.out.println("main thread seq of " + i + ", loop of " + loop);
  38. }
  39. bool = true;
  40. condition.signal();//this.notify();
  41. } finally {
  42. lock.unlock();
  43. }
  44. }
  45. public /*synchronized*/ void sub(int loop) throws InterruptedException {
  46. lock.lock();
  47. try {
  48. while(!bool) {
  49. condition.await();//this.wait();
  50. }
  51. for(int i = 0; i < 10; i++) {
  52. System.out.println("sub thread seq of " + i + ", loop of " + loop);
  53. }
  54. bool = false;
  55. condition.signal();//this.notify();
  56. } finally {
  57. lock.unlock();
  58. }
  59. }
  60. }

在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。

这样看来,Condition和传统的线程通信没什么区别,Condition的强大之处在于它可以为多个线程间建立不同的Condition,下面引入API中的一段代码,加以说明。

  1. class BoundedBuffer {
  2. final Lock lock = new ReentrantLock();//锁对象
  3. final Condition notFull = lock.newCondition();//写线程条件
  4. final Condition notEmpty = lock.newCondition();//读线程条件
  5.  
  6. final Object[] items = new Object[100];//缓存队列
  7. int putptr/*写索引*/, takeptr/*读索引*/, count/*队列中存在的数据个数*/;
  8.  
  9. public void put(Object x) throws InterruptedException {
  10. lock.lock();
  11. try {
  12. while (count == items.length)//如果队列满了
  13. notFull.await();//阻塞写线程
  14. items[putptr] = x;//赋值
  15. if (++putptr == items.length) putptr = 0;//如果写索引写到队列的最后一个位置了,那么置为0
  16. ++count;//个数++
  17. notEmpty.signal();//唤醒读线程
  18. } finally {
  19. lock.unlock();
  20. }
  21. }
  22.  
  23. public Object take() throws InterruptedException {
  24. lock.lock();
  25. try {
  26. while (count == 0)//如果队列为空
  27. notEmpty.await();//阻塞读线程
  28. Object x = items[takeptr];//取值
  29. if (++takeptr == items.length) takeptr = 0;//如果读索引读到队列的最后一个位置了,那么置为0
  30. --count;//个数--
  31. notFull.signal();//唤醒写线程
  32. return x;
  33. } finally {
  34. lock.unlock();
  35. }
  36. }
  37. }

这是一个处于多线程工作环境下的缓存区,缓存区提供了两个方法,put和take,put是存数据,take是取数据,内部有个缓存队列,具体变量和方法说明见代码,这个缓存区类实现的功能:有多个线程往里面存数据和从里面取数据,其缓存队列(先进先出后进后出)能缓存的最大数值是100,多个线程间是互斥的,当缓存队列中存储的值达到100时,将写线程阻塞,并唤醒读线程,当缓存队列中存储的值为0时,将读线程阻塞,并唤醒写线程,下面分析一下代码的执行过程:

1. 一个写线程执行,调用put方法;

2. 判断count是否为100,显然没有100;

3. 继续执行,存入值;

4. 判断当前写入的索引位置++后,是否和100相等,相等将写入索引值变为0,并将count+1;

5. 仅唤醒读线程阻塞队列中的一个;

6. 一个读线程执行,调用take方法;

7. ……

8. 仅唤醒写线程阻塞队列中的一个。

这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间。

本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7481142,转载请注明。

Condition-线程通信更高效的方式的更多相关文章

  1. Condition线程通信(七)

    前言:对于线程通信,使用synchronized时使用wait.notify和notifyAll来实行线程通信.而使用Lock如何处理线程通信呢?答案就是本片的主角:Condition. 一.Cond ...

  2. 通过一道面试题了解Condition线程通信

    Condition Condition接口描述了可能会与锁有关联的条件变量.这些变量在用法与使用Object.wait访问的隐式监视器类似,但提供了更强大的功能.需要特别指出的是,单个Lock可能与多 ...

  3. java 多线程 day13 condition 线程通信

    /** * Created by chengtao on 17/12/5. * Condition 类似 wait和notify,解决线程间的同步问题 */ import java.util.conc ...

  4. Condition线程通信_生产者消费者案例

    ①Condition 接口描述了可能会与锁有关联的条件变量. 这些变量在用 法上与使用 Object.wait 访问的隐式监视器类似,但提供了更强大的 功能. 需要特别指出的是,单个 Lock 可能与 ...

  5. JAVA基础知识之多线程——线程通信

    传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...

  6. Java并发基础--线程通信

    java中实现线程通信的四种方式 1.synchronized同步 多个线程之间可以借助synchronized关键字来进行间接通信,本质上是通过共享对象进行通信.如下: public class S ...

  7. Condition控制线程通信

    Condition控制线程通信 一.前言 java.util.concurrent.locks.Condition 接口描述了可能会与锁有关联的条件变量.这些变量在用法上与使用Object.wait ...

  8. 6.显示锁Lock 和 线程通信Condition

    显示锁 Lock 一.用于解决多线程 安全问题的方式: synchronized:   1.同步代码块      2.同步方法 jdk1.5 后:第三种:同步锁Lock  (注意:同步(synchro ...

  9. 并发编程系列小结(线程安全,synchronized,脏读,线程间的通信wait/notify,线程的三种实现方式Demo,可替代wait/notify的方法)

    线程安全: 当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法就是线程安全的) synchronized: 可以在任意对象或方法上加锁,而加锁的这段代码称为 ...

随机推荐

  1. 以非root权限安装nginx及运行

    本章主要讲如何在无root权限(包含无sudo权限)条件下于centos命令行中安装nginx以及在大于1024的端口(这里用8080)上运行. 1. 安装 两种方式,一是下载预编译好的rpm包安装, ...

  2. PHP中的cookie创建取回删除;

    <?php $expire=time()+3600;//设置过期cookie时间 setcookie('yaoyuan',"webyaoyuan",$expire);//se ...

  3. radio的change事件

    radio的change事件 <scripttype="text/javascript"> $(document).ready(function(){ $(" ...

  4. [Unity官方文档翻译]ScrollRect

    官方地址:http://docs.unity3d.com/Manual/script-ScrollRect.html 一边学习一边翻译不知效率如何= = Scroll Rect 在小区域里展示大量内容 ...

  5. C++ 常见问题

    1:保证编译后方法名不被修改:  The: extern "C" { function declarations here in h file } will disable C++ ...

  6. C# 实现的多线程异步Socket数据包接收器框架

    转载自Csdn : http://blog.csdn.net/jubao_liang/article/details/4005438 几天前在博问中看到一个C# Socket问题,就想到笔者2004年 ...

  7. JS 頁面實時更新時間

    function startTime() { var today = new Date(); //定义日期对象 var yyyy = today.getFullYear(); //通过日期对象的get ...

  8. C# 虚方法 抽象方法 接口

    虚方法:virtu 注意的几点: 1,父类中如果有方法让子类重写,则可以将该方法标记为virtual 2.虚方法在父类中必须有实现,哪怕是空实现 3虚方法子类可以重写,也可以不重写 4.如果类是抽象类 ...

  9. CSS Margin(外边距)

    CSS Margin(外边距)属性定义元素周围的空间. Margin margin清除周围的元素(外边框)的区域.margin没有背景颜色,是完全透明的 margin可以单独改变元素的上,下,左,右边 ...

  10. 系统设计 - 使用面向 iOS 的本机插件扩展

    本文转自:http://www.cnblogs.com/zhwl/archive/2013/07/26/3217155.html 本文细致探讨了 Xcode(以 iOS 设备为目标)中的 PhoneG ...