zoukankan      html  css  js  c++  java
  • 生产者消费者两种实现:wait/notifyAll和Lock/Condition

    1.wait/notifyAll

    /**
     * 面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
     * 能够支持2个生产者线程以及10个消费者线程的阻塞调用
     * 
     * 使用wait和notify/notifyAll来实现
     * 
     * @author cx
     */
    package com.chanx.demo.example.c_021;
    
    import java.util.LinkedList;
    import java.util.concurrent.TimeUnit;
    
    public class MyContainer1<T> {
        final private LinkedList<T> lists = new LinkedList<>();
        final private int MAX = 10; //最多10个元素
        private int count = 0;
        
        
        public synchronized void put(T t) {
            while(lists.size() == MAX) { //想想为什么用while而不是用if?
                try {
                    this.wait(); //effective java
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            lists.add(t);
            ++count;
            this.notifyAll(); //通知消费者线程进行消费
        }
        
        public synchronized T get() {
            T t = null;
            while(lists.size() == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            t = lists.removeFirst();
            count --;
            this.notifyAll(); //通知生产者进行生产
            return t;
        }
        
        public static void main(String[] args) {
            MyContainer1<String> c = new MyContainer1<>();
            //启动消费者线程
            for(int i=0; i<10; i++) {
                new Thread(()->{
                    for(int j=0; j<5; j++) System.out.println(c.get());
                }, "c" + i).start();
            }
            
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //启动生产者线程
            for(int i=0; i<2; i++) {
                new Thread(()->{
                    for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
                }, "p" + i).start();
            }
        }
    }

    2.Lock/Condition

    /**
     * 面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
     * 能够支持2个生产者线程以及10个消费者线程的阻塞调用
     * 
     * 使用wait和notify/notifyAll来实现
     * 
     * 使用Lock和Condition来实现
     * 对比两种方式,Condition的方式可以更加精确的指定哪些线程被唤醒
     * 
     * @author cx
     */
    package com.chanx.demo.example.c_021;
    
    import java.util.LinkedList;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyContainer2<T> {
        final private LinkedList<T> lists = new LinkedList<>();
        final private int MAX = 10; //最多10个元素
        private int count = 0;
        
        private Lock lock = new ReentrantLock();
        private Condition producer = lock.newCondition();
        private Condition consumer = lock.newCondition();
        
        public void put(T t) {
            try {
                lock.lock();
                while(lists.size() == MAX) { //想想为什么用while而不是用if?
                    producer.await();
                }
                
                lists.add(t);
                ++count;
                consumer.signalAll(); //通知消费者线程进行消费
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        
        public T get() {
            T t = null;
            try {
                lock.lock();
                while(lists.size() == 0) {
                    consumer.await();
                }
                t = lists.removeFirst();
                count --;
                producer.signalAll(); //通知生产者进行生产
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return t;
        }
        
        public static void main(String[] args) {
            MyContainer2<String> c = new MyContainer2<>();
            //启动消费者线程
            for(int i=0; i<10; i++) {
                new Thread(()->{
                    for(int j=0; j<5; j++) System.out.println(c.get());
                }, "c" + i).start();
            }
            
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //启动生产者线程
            for(int i=0; i<2; i++) {
                new Thread(()->{
                    for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
                }, "p" + i).start();
            }
        }
    }
  • 相关阅读:
    通过输入方式在Android上进行微博OAuth登录
    Android应用集成支付宝接口的简化
    Tomcat启动时报 java.lang.OutOfMemoryError: Java heap space
    Myeclipse中 Exploded location overlaps an existing deployment解决办法
    SVN提交项目时版本冲突解决方案
    Jsp过滤器Filter配置过滤类型汇总
    myeclipse修改jsp文件的名称之后,再也打不开的解决方案
    文件上传之 commons-fileupload(二)
    文件上传之 commons-fileupload(一)
    常见池化技术
  • 原文地址:https://www.cnblogs.com/cxhfuujust/p/10275795.html
Copyright © 2011-2022 走看看