• Java核心知识点学习----使用Condition控制线程通信


    一.需求

    实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.

    即:A->B->C---A->B->C---A->B->C

    二.实现

    1.分析

    在前面文章java核心知识点学习----多线程并发之线程间的通信,notify,wait,曾实现过需求两个线程间隔循环的例子.涉及到3个线程就使用之间的方法就有点麻烦了,这里借着刚学的Lock锁可以很方便实现互斥,但如何实现三个线程间的通信呢?

    2.实现效果

    3.实现代码

    package com.amos.concurrent;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @ClassName: ThreadSynchronizedConnect
     * @Description:实现线程间的通信,需求:主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.A->B->C---A->B->C---A->B->C
     * @author: amosli
     * @email:hi_amos@outlook.com
     * @date Apr 20, 2014 4:39:44 PM
     */
    public class ThreeConnect {
    
        public static void main(String[] args) {
            final Business business = new Business();
            new Thread(new Runnable() {
                public void run() {
                    for (int i = 0; i < 3; i++) {
                        business.sub2(i);
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                public void run() {
                    for (int i = 0; i < 3; i++) {
                        business.sub3(i);
                    }
                }
            }).start();
    
            for (int i = 0; i < 3; i++) {
                business.main(i);
            }
        }
    
        static class Business {
            Lock lock = new ReentrantLock();
            Condition conditionmain = lock.newCondition();
            Condition conditionsub2 = lock.newCondition();
            Condition conditionsub3 = lock.newCondition();
    
            private int current = 1;
    
            // 子方法2
            public void sub2(int i) {
                lock.lock();
                try {
                    if (current != 2) {// 如果不为true,将等待,Blocked状态
                        try {
                            conditionsub2.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    for (int j = 0; j < 2; j++) {
                        System.out.println("sub2 thread:" + j + "  loop:" + i);
                    }
                    current = 3;
                    conditionsub3.signal();// 唤醒3
                } finally {
                    lock.unlock();
                }
            }
    
            // 子方法3
            public void sub3(int i) {
                lock.lock();
                try {
                    if (current != 3) {// 如果不为true,将等待,Blocked状态
                        try {
                            conditionsub3.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    for (int j = 0; j < 2; j++) {
                        System.out.println("sub3 thread:" + j + "  loop:" + i);
                    }
                    current = 1;
                    conditionmain.signal();
                } finally {
                    lock.unlock();
                }
            }
    
            // 主方法
            public void main(int i) {
                lock.lock();
                try {
                    if (current != 1) {
                        try {
                            conditionmain.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    for (int j = 0; j < 3; j++) {
                        System.out.println("main thread:" + j + "  loop:" + i);
                    }
                    current = 2;
                    conditionsub2.signal();
                } finally {
                    lock.unlock();
                }
    
            }
    
        }
    
    }

    4.代码说明

    上面的代码中用的是Lock进行加锁操作的,然后线程间的通信没有用之前的wait(),notify()方法用的是Conditon的await()和signal()

    为什么要使用Condition??

    如果程序中不使用synchronized关键字来保证同步,而是使用Lock对象来保证数据同步,则系统中不存在隐式的同步监视器,也就不能使用wait().notify()方法进行线程通信了.

    因为使用了Lock对象,所以要使线程间通信,可以使用Condition进行控制线程间通信.

    Condition将同步监视器方法(wait(),notify(),notifyall()等)分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set).

    创建一个Condition,只需要lock.newCondition()即可,lock是已经new 好的ReentrantLock()对象.

    >>await()方法与wait()功能类似,都是将线程加入到阻塞状态.

    >>signal()方法与notify()方法类似,都是唤醒等待中的线程,只是signal()方法可以指定具体要唤醒的线程.

    >>signalAll()方法与notifyAll()方法类似,都是唤醒所有等待中的线程.

    5.扩展

    1).下面是简单的对比,notify和signal等方法的对比,其效果是完全一样的.

    package com.amos.concurrent;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @ClassName: ConditionConnect
     * @Description:用condition替代wait,notify实现线程间的通信,需求:子线程循环10次,主线程循环100次,这样间隔循环50次.
     * @author: amosli
     * @email:hi_amos@outlook.com
     * @date Apr 24, 2014 12:07:23 AM
     */
    public class ConditionConnect {
    
        public static void main(String[] args) {
            final Business business = new Business();
            new Thread(new Runnable() {
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        business.sub(i);
                    }
                }
            }).start();
    
            for (int i = 0; i < 5; i++) {
                business.main(i);
            }
        }
    
        /*
         * 经验:要用到共同数据(包括同步锁)的若干方法,应该归在同一个类身上,这样方便实现,高类聚和程序的健状性上.
         */
        static class Business {
            private boolean is_sub = true;
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
    
            // 子方法
            public void sub(int i) {
                lock.lock();
                try {
                    while (!is_sub) {// 如果不为true,将等待,Blocked状态
                        try {
                            // this.wait();
                            condition.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    for (int j = 0; j < 2; j++) {
                        System.out.println("sub thread:" + j + "  loop:" + i);
                    }
                    is_sub = false;
                    // this.notify();//唤醒正在等待的线程
                    condition.signal();
                } finally {
                    lock.unlock();
                }
    
            }
    
            // 主方法
            public void main(int i) {
                lock.lock();
                try {
                    while (is_sub) {
                        try {
                            // this.wait();
                            condition.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
    
                    for (int j = 0; j < 10; j++) {
                        System.out.println("main thread:" + j + "  loop:" + i);
                    }
                    is_sub = true;
                    // this.notify();
                    condition.signal();
                } finally {
                    lock.unlock();
                }
    
            }
        }
    
    }

    2).官方提供的例子

    做了简单的修改:

     先看效果:

    再看代码:

    package com.amos.concurrent;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /** 
    * @ClassName: ConditionTest 
    * @Description: 官方提供的例子
    * @author: amosli
    * @email:hi_amos@outlook.com
    * @date Apr 24, 2014 12:40:58 AM  
    */
    public class ConditionTest {
        public static void main(String[] args) throws Exception {
            BoundedBuffer buffer = new BoundedBuffer();
            buffer.put("hi_amos");
            for(int i=0;i<3;i++){
                buffer.put(i);
                System.out.println("take:"+buffer.take());
            }
            
        }
        static  class BoundedBuffer {
               final Lock lock = new ReentrantLock();
               final Condition notFull  = lock.newCondition(); 
               final Condition notEmpty = lock.newCondition(); 
    
               final Object[] items = new Object[100];
               int putptr, takeptr, count;
               
               //设值
               public void put(Object x) throws InterruptedException {
                 lock.lock();
                 try {
                   while (count == items.length)
                     notFull.await();
                   items[putptr] = x;
                   if (++putptr == items.length) putptr = 0;
                   ++count;
                   notEmpty.signal();
                 } finally {
                   lock.unlock();
                 }
               }
    
               //取值
               public Object take() throws InterruptedException {
                 lock.lock();
                 try {
                   while (count == 0)
                     notEmpty.await();
                   Object x = items[takeptr];
                   if (++takeptr == items.length) takeptr = 0;
                   --count;
                   notFull.signal();
                   return x;
                 } finally {
                   lock.unlock();
                 }
               }
             }
    }

    思考:例子中为什么要new 2个condition??

  • 相关阅读:
    ubuntu 更新软件
    如何在linux(lubuntu)下搭建C/C++开发环境
    Linux下如何查看版本信息
    知识点笔记
    Require.js中使用jQuery 插件
    async中常用总结
    node.js在遇到“循环+异步”时的注意事项
    前端性能优化
    生产/消费者问题
    线程与内存
  • 原文地址:https://www.cnblogs.com/amosli/p/3684408.html
Copyright © 2020-2023  润新知