• java实现生产者消费者模式


    生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。

    使用synchronized关键字实现线程同步

    在使用wait()和notifyAll()方法时,应注意将wait()方法放入循环中,否则会产生虚假唤醒问题。

    /**
     * Created by 吴海飞 on 2017-1-23.
     */
    public class TestProductAndConsumer {
        public static void main(String[] args){
            Clerk clerk = new Clerk();
            Productor pro = new Productor(clerk);
            Consumer consumer = new Consumer(clerk);
            new Thread(pro,"生产者A").start();
            new Thread(consumer,"消费者B").start();
        }
    }
    
    /**
     * 店员,可以进货与销售货物
     */
    class Clerk{
    
        private int product = 0;
    
        /**
         * 进货的方法
         */
        public synchronized void get(){
            while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
                System.out.println("产品已满!");
    
                try {
                    this.wait();//等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":" + ++product);
            this.notifyAll();//唤醒线程
        }
    
        /**
         * 销售的方法
         */
        public synchronized void sale(){
            while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
                System.out.println("缺货……");
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":"+ --product);
            this.notifyAll();
        }
    }
    
    /**
     * 生产者
     */
    class Productor implements Runnable{
    
        private Clerk clerk;
    
        public Productor(Clerk clerk){
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.get();
            }
        }
    }
    
    /**
     * 消费者
     */
    class Consumer implements Runnable{
    
        private Clerk clerk;
    
        public Consumer(Clerk clerk){
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++){
                clerk.sale();
            }
        }
    }

    使用同步锁实现线程同步问题

    使用同步锁时应注意lock()与unlock()方法的同步使用。

    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 使用ReentrantLock实现生产者消费者问题
     * Created by 吴海飞 on 2017-1-23.
     */
    public class TestReentrantLock {
        public static void main(String[] args){
            Clerk clerk = new Clerk();
            Productor pro = new Productor(clerk);
            Consumer consumer = new Consumer(clerk);
    
            new Thread(pro,"生产者A").start();
            new Thread(consumer,"消费者B").start();
            new Thread(pro,"生产者C").start();
            new Thread(consumer,"消费者D").start();
        }
    }
    
    class Clerk{
        private Lock lock = new ReentrantLock();//获取同步锁
        private Condition condition = lock.newCondition();
        private int product = 0;
    
    
    /**
     * 进货的方法
     */
    
        public void get(){
            lock.lock();//打开锁
            try{
                while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
                    System.out.println("产品已满!");
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + ":" + ++product);
                condition.signalAll();
            }finally {
                lock.unlock();//关闭锁
            }
    
        }
    
    
    /**
     * 销售的方法
     */
    
        public void sale(){
            lock.lock();//加锁
            try {
                while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
                    System.out.println("缺货……");
                    try {
                        condition.await();//等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + ":"+ --product);
                condition.signalAll();//唤醒等待
            }finally {
                lock.unlock();//释放锁
            }
    
        }
    }
    
    
    /**
     * 生产者
     */
    
    class Productor implements Runnable{
    
        private Clerk clerk;
    
        public Productor(Clerk clerk){
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.get();
            }
        }
    }
    
    
    /**
     * 消费者
     */
    
    class Consumer implements Runnable{
    
        private Clerk clerk;
    
        public Consumer(Clerk clerk){
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++){
                clerk.sale();
            }
        }
    }
    
  • 相关阅读:
    Java-Class-@I:org.springframework.web.bind.annotation.RequestBody.java
    Java-Class-@I:org.springframework.validation.annotation.Validated.java
    Java-Class-@I:org.springframework.beans.factory.annotation.Autowired.java
    Java-Class-@I:org.springframework.stereotype.Service.java
    Murano环境搭建、使用介绍和思考
    简洁经常使用权限系统的设计与实现(一):构造权限菜单树的N(N&gt;=4)种方法
    Android 依赖注入: Dagger 2 实例解说(一)
    mybatis的#和$的差别
    国内外优秀呼叫中心系统简单介绍
    openWRT学习之LUCI之中的一个helloworld演示样例
  • 原文地址:https://www.cnblogs.com/haifeiWu/p/9079587.html
Copyright © 2020-2023  润新知