标签:des style blog io color ar java for sp
在多线程以及并发工具类中,常用的一种思想就是生产者消费者模式,生产者负责生产物品,将物品放到传送带,消费者负责获取传送带的物品,消费物品。现在只考虑最简单的情况,传送带上只允许放一个物品。
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就是告知线程可以抢占对象内置锁了)。
标签:des style blog io color ar java for sp
原文地址:http://www.cnblogs.com/seanvon/p/4071756.html