JAVA多线程之——线程通信 Condition

30 篇文章 0 订阅

线程的通信
前面学习了用wait/notify的方式进行线程通信。今天学习一种更加强大的线程通信方式Condition.Condition的强大之处就是可以为线程建立不同的Condition。然后可以唤醒任意指定阻塞的线程。Condition之所以能为一个线程建立不同的Condition,是因为它也维护着一个阻塞的条件队列。它跟AQS等待队列通过线程的等待、唤醒建立关系。
1.每当AQS队列中的线程调用Condition.await()方法,AQS就会把当前线程从队列中移除,并加入到Condition队列的尾部并阻塞,然后等待唤醒。
2.每当AQS队列中线程对Condition队列中的某个阻塞线程进行了Condition.sinal()方法,Condition队列就会把该线程从队列中移除,线程加入AQS等待队列末尾,等待获取锁。
通过Condition实现多线程的消费者、生产者模式来进一步理解:


public class ConditionTest {


    static class Depot{

        private int size;
        private ReentrantLock  lock = null;
        private  Condition  notEmptyCondition = null ;
        private  Condition  notFullCondition = null;
        private  List<Integer> depots;


        public Depot(int size) {
            this.size = size;
            lock = new ReentrantLock();
            notEmptyCondition = lock.newCondition();
            notFullCondition = lock.newCondition();
            depots = new LinkedList<Integer>();
        }


        /**
         * 每次生产count个产品
         * @param count
         */
        public void producer(int count) {
            lock.lock();
            try {
                while(depots.size()  > 0){
                    System.out.println("仓库已经有铲产品了,可以开始消费了");
                    notFullCondition.await();  //仓库满了进行等待消费
                }
            int actCount = (count + depots.size()) > size ? (size - depots.size()) : count; //如果生产的数量和现有的数量大于总数,就只生产仓库剩余的最大容量数
           System.out.println(Thread.currentThread().getName() + "线程开始生产");
            for(int i = 0; i < actCount; i++ ) {
                depots.add(i);
             }
            System.out.println(Thread.currentThread().getName() + "生产完毕,当前仓库有" + depots.size() + "个产品");
             notEmptyCondition.signal();
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }



        public void consumer(int count) {
            lock.lock();
            try {
                while(depots.size() == 0) {
                    System.out.println("当前仓库为空,等待生产");
                    notEmptyCondition.await();
                }
                int actCount = (depots.size() > count ) ? count : depots.size();//如果当前仓库剩余容量大于消费容量,就消费消费个,如果消费的容量比仓库剩余容量大,就把剩余的都消费掉。
                  System.out.println(Thread.currentThread().getName() + "线程开始消费");
                Iterator<Integer> iterator = depots.iterator();
                while(iterator.hasNext() && actCount > 0  ) {
                    iterator.next();
                    iterator.remove();
                    actCount--;
                }
                System.out.println(Thread.currentThread().getName() + "消费完毕,当前仓库有" + depots.size() + "个产品");
                notFullCondition.signal();

            } catch (Exception e) {
                e.printStackTrace();
            }finally {

                lock.unlock();
            }


        }

    }

    public static void main(String[] args) {
        final Depot depot = new Depot(100);

        for(int i = 0; i < 30; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        depot.producer(40);
                    }
                }
            },"producer-" + i );
            thread.start();
        }


        for(int i = 0; i < 30; i++) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        depot.consumer(80);
                    }
                }
            },"consumer-" + i);
            thread1.start();
        }

    }

}

某一次运行部分结果

producer-20线程开始生产
producer-20生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-2线程开始消费
cusume-2消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-21线程开始生产
producer-21生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-28线程开始消费
cusume-28消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-15线程开始生产
producer-15生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-11线程开始消费
cusume-11消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-24线程开始生产
producer-24生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-14线程开始消费
cusume-14消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-19线程开始生产
producer-19生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-4线程开始消费
cusume-4消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-25线程开始生产
producer-25生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-15线程开始消费
cusume-15消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-8线程开始生产
producer-8生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-20线程开始消费
cusume-20消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-29线程开始生产
producer-29生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-5线程开始消费
cusume-5消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-1线程开始生产
producer-1生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-0线程开始消费
cusume-0消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-26线程开始生产
producer-26生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-18线程开始消费
cusume-18消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-16线程开始生产
producer-16生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-19线程开始消费
cusume-19消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-3线程开始生产
producer-3生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-12线程开始消费
cusume-12消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-7线程开始生产
producer-7生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-22线程开始消费
cusume-22消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-11线程开始生产
producer-11生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-26线程开始消费
cusume-26消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-2线程开始生产
producer-2生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-1线程开始消费
cusume-1消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-28线程开始生产
producer-28生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-23线程开始消费
cusume-23消费完毕,当前仓库有0个产品
当前仓库为空,等待生产
producer-10线程开始生产
producer-10生产完毕,当前仓库有40个产品
仓库已经有铲产品了,可以开始消费了
cusume-27线程开始消费
cusume-27消费完毕,当前仓库有0个产品
当前仓库为空,等待生产

上面是简单模拟生产者消费者的例子。当然其中还有很多变化。还有就是用List来做存储。这个在多线程高并发环境下是不安全的等等。以后会学习JUC下的集合以及一些并发类。就能写出越来越安全的生产者消费真模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值