• Java精通并发-通过Condition实现线程间通信实例剖析【下】


    在上一次https://www.cnblogs.com/webor2006/p/12083720.html完成了Condition线程同步的实例,但是还木有对其运行流程进行分析,所以这次对它进行一个细致的分析,并且再对其代码做一些调整加深对其的印象,先回顾一下上次的代码:

    public class MyTest2 {
        public static void main(String[] args) {
            BoundedContainer boundedContainer = new BoundedContainer();
    
            //利用java8的流来产生多个生产者线程
            IntStream.range(0, 10).forEach(i -> new Thread(() -> {
                try {
                    boundedContainer.put("hello");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start());
            //利用java8的流来产生多个生产者线程
            IntStream.range(0, 10).forEach(i -> new Thread(() -> {
                try {
                    boundedContainer.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start());
        }
    }
    
    class BoundedContainer {
        private String[] elements = new String[10];
        private Lock lock = new ReentrantLock();
        private Condition notEmptyCondition = lock.newCondition();
        private Condition notFullCondition = lock.newCondition();
        private int elementCount;//elements数组中已有的元素数量
        private int putIndex;
        private int takeIndex;
    
        public void put(String element) throws InterruptedException {
            this.lock.lock();
            try {
                while (this.elementCount == this.elements.length) {
                    notFullCondition.await();
                }
    
                elements[putIndex] = element;
                if (++putIndex == this.elements.length) {
                    putIndex = 0;
                }
                ++elementCount;
                System.out.println("put method: " + Arrays.toString(elements));
    
                notEmptyCondition.signal();
    
            } finally {
                this.lock.unlock();
            }
        }
    
        public String take() throws InterruptedException {
            this.lock.lock();
    
            try {
                while (0 == this.elementCount) {
                    notEmptyCondition.await();
                }
                String element = elements[takeIndex];
                elements[takeIndex] = null;
    
                if (++takeIndex == elements.length) {
                    takeIndex = 0;
                }
    
                --elementCount;
                System.out.println("take method: " + Arrays.toString(elements));
    
                notFullCondition.signal();
    
                return element;
    
            } finally {
                this.lock.unlock();
            }
        }
    }

    其运行结果如下:

    所以在结果的输出上也存在一个先后顺序了,先打印的是存放相关的输出,再打印的取元素,如下:

    而从输出的结果可以看到,存放元素的位置和取出元素的位置如预期,都是按着上一次的位置进行的,那如果咱们这样巅倒一下顺序呢?

     

    再运行:

    这次的输出就木有这么工整了,原因是由于在还木有元素的情况下先消费肯定会阻塞,所以:

    接着就不继续细分析了,基本上就是按着上面说的原则进行执行的,好,下面继续来修改一下生产者与消费者的线程数,来对写的程序做做测试:

    嗯,没啥问题,先生产了5个数据,然后再消费了5个,接下来再来修改:

    结果:

    put method: [hello, null, null, null, null, null, null, null, null, null]
    put method: [hello, hello, null, null, null, null, null, null, null, null]
    put method: [hello, hello, hello, null, null, null, null, null, null, null]
    put method: [hello, hello, hello, hello, null, null, null, null, null, null]
    put method: [hello, hello, hello, hello, hello, null, null, null, null, null]
    put method: [hello, hello, hello, hello, hello, hello, null, null, null, null]
    put method: [hello, hello, hello, hello, hello, hello, hello, null, null, null]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, null, null]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, null]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [null, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, null, hello, hello, hello, hello, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, null, hello, hello, hello, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, null, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, null, null, hello, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, null, hello, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, hello, hello, null, hello, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, hello, hello, hello, null, hello, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, hello, hello, hello, hello, null, hello, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, hello, hello, hello, hello, hello, null, hello]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, null]
    put method: [hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [null, hello, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [null, null, hello, hello, hello, hello, hello, hello, hello, hello]
    take method: [null, null, null, hello, hello, hello, hello, hello, hello, hello]
    take method: [null, null, null, null, hello, hello, hello, hello, hello, hello]
    take method: [null, null, null, null, null, hello, hello, hello, hello, hello]
    take method: [null, null, null, null, null, null, hello, hello, hello, hello]
    take method: [null, null, null, null, null, null, null, hello, hello, hello]
    take method: [null, null, null, null, null, null, null, null, hello, hello]
    take method: [null, null, null, null, null, null, null, null, null, hello]
    take method: [null, null, null, null, null, null, null, null, null, null]
    
    Process finished with exit code 0

    20个生产者与20个消费者执行完之后,最终肯定是把数组中的元素都给消费掉了,妥妥的。继续来修改程序进行测试:

    那如果反过来呢?

    运行:

    以上就是关于Condition这个例子解析,说实话要实现这样一个功能并不是很简单的,但是消化好这个例子对于Condition的理解是非常好的。

  • 相关阅读:
    Microsoft.VisualBasic.PowerPacks相关错误解决办法
    GridView绑定技巧终结者
    类型初始值设定项引发异常处理办法
    目前为目最全的CURL中文说明CURL
    [转]大型网站架构之优酷篇
    [原]ecshop代码分析二(缓存处理)
    [转]大型网站架构不得不考虑的10个问题
    [原]ecshop代码分析一(init.php文件)
    发布一款坐标转换软件
    坐标换算软件操作方法及下载地址
  • 原文地址:https://www.cnblogs.com/webor2006/p/12084454.html
Copyright © 2020-2023  润新知