zoukankan      html  css  js  c++  java
  • 生产者消费者模式的java实现(实现一)

    在多线程以及并发工具类中,常用的一种思想就是生产者消费者模式,生产者负责生产物品,将物品放到传送带,消费者负责获取传送带的物品,消费物品。现在只考虑最简单的情况,传送带上只允许放一个物品。

    1、传送带为空,则允许生产者放置物品,否则不许放(生产者线程wait)。

    2、生产者放置完物品后,通知消费者可以拿了(线程通信,notify 或者notifyAll)。

    2、传送带不空,则允许消费者拿物品,否则不许拿(消费者线程wait)。

    3、消费者拿走物品后,通知生产者可以继续生产(线程通信,notify 或者notifyAll)。

    package com.smikevon.concurrent;
    
    import java.util.Random;
    
    /**
     * @description: 生产者消费者模式,通过wait和notify方式来实现
     * @date       : 2014年9月12日 上午11:39:31
     */
    public class ProducerConsumer_01 {
    
        public static void main(String[] args) {
            Drop drop = new Drop();
            new Thread(new Producer(drop)).start();
            new Thread(new Consumer(drop)).start();
        }
    
    }
    
    /**
     * @description: 传送带,只能有一个物品(message)在上面
     * @date       : 2014年9月12日 下午12:03:08
     */
    class Drop{
    
        private String message;
        private boolean empty = true;
    
        public synchronized String take() throws InterruptedException{
            while(empty){
                wait();
            }
            empty = true;
            notifyAll();
            return message;
        }
    
        public synchronized void put(String message) throws InterruptedException{
            while(!empty){
                wait();
            }
            this.message = message;
            empty = false;
            notifyAll();
        }
    
    }
    
    /**
     *
     * @description: 生产者随机放入字符串
     * @date       : 2014年9月12日 上午11:53:27
     */
    class Producer implements Runnable {
    
        private Drop drop;
    
        public Producer(Drop drop) {
            this.drop = drop;
        }
    
        public void run() {
            String[] messages = {
                "我是",
                "一名程序员",
                "我很骄傲",
                "也很自豪",
                "爱岗敬业",
                "勤劳奉献",
                "无怨无悔",
                "奉献青春",
                "希望通过学习",
                "提升",
                "自己",
                "done",
            };
            try {
                for(int i=0;i<messages.length;i++){
                    System.out.format("%s: 放入信息-----------%s %n",Thread.currentThread().getName(),messages[i]);
                    drop.put(messages[i]);
                    Thread.sleep(new Random(System.currentTimeMillis()).nextInt(5000));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    /**
     * @description: 消费者,有字符串,就取出来
     * @date       : 2014年9月12日 下午12:02:35
     */
    class Consumer implements Runnable{
    
        private Drop drop;
    
        Consumer(Drop drop){
            this.drop = drop;
        }
    
        public void run() {
            try {
                String message = "";
                System.out.println(drop);
                while(!(message = drop.take()).equals("done")){
                    System.out.format("%s: 取出信息-------------%s %n",Thread.currentThread().getName(),message);
                    Thread.sleep(new Random(System.currentTimeMillis()).nextInt(5000));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

    在线程wait的代码处都采用了循环测试条件(专业名称叫条件谓词),如下

    while(!empty){
                wait();
            }

      是因为在另一个线程notifyAll,唤醒本线程后,无法确认此时就一定满足测试条件。两个线程不会有问题,但是在更多线程的时候就会出问题,因为你无法确认自己就是被生产者线程唤醒的,可能在唤醒之前已经有其他线程改变过状态变量(本类就是Drop里的message),这样就会出现异常,因此需要在被唤醒后立马测试下条件是否已经满足。将一致性保障交给竞态条件(notifyAll就是等待的线程竞争获取对象的锁)是不良的变成习惯。

      下面一节(实现二)会介绍ReenrantLock,里面将等待与唤醒条件进行了细分,让你可以赋予条件真实的意义,而不只将意义绑定到锁的持有上(wait是告诉本线程挂起 和 notify就是告知线程可以抢占对象内置锁了)。

  • 相关阅读:
    使用form插件 和ajax 结合使用 没有调用success的原因
    不使用插件的ajax 上传文件
    struts2 使用ajax进行图片上传
    Java输入输出流详解
    SSM框架整合(Spring+SpringMVC+MyBatis+Oracle)
    Java WEB开发环境搭建以及创建Maven Web项目
    java连接Oracle数据库
    java轻量级IOC框架Guice
    Java String字符串方法
    python入门
  • 原文地址:https://www.cnblogs.com/seanvon/p/4071756.html
Copyright © 2011-2022 走看看