之前学习多线程问题遇到的最大的难度就是,很多;生产者消费者模式是比较经典的多线程问题,看似 不难,但实际上有很多地方值得注意的。
首先是几个问题
问题1 一共有哪些对象?
生产者与消费者是肯定有的,生产者与消费者之间还有一个缓冲区对象,用以保存生产与消费的目标,还有一个对象就是主线程对象,用来运行多个线程的。
追问:为什么要有一个缓冲区对象?
答:为了实现生产者与消费者解耦,互补依赖或者关联。
追问:每个对象都包含哪些变量与方法?
答:生产者包含缓冲区对象并在run()方法里面执行生产调度命令;消费者含缓冲区对象并在run()方法里面执行消费调度命令;缓冲区则保存产品的数组/Stack/Queue以及生产与消费的具体指令;主线程对象则用来实现生产者与消费者线程创建与运行的。
问题2 哪些方法需要同步?
缓冲区对象的生产与消费必须实现同步。
我在进行研究的时候,会出现如下错误的代码:
/** * 项目名称: * 文件说明: * 主要特点:生产者消费者模式 * 版本号:1.0 * 制作人:lcx * 创建时间:2013-12-3 **/ package treadgame; import java.util.Stack; /** * @author lcx * */ public class Producer_Consumer1 { public static void main(String[] args) { Stack<String> apples=new Stack<String>(); Thread td1=new Thread(new Producer1("生产者1",apples)); Thread td2=new Thread(new Consumer1("消费者",apples)); td2.start(); td1.start(); } } class Producer1 implements Runnable { String name; Stack<String> apples; public Producer1(String name,Stack<String> apples) { this.name=name; this.apples=apples; } public synchronized void produce(String apple) throws Exception { // System.out.println("生产者 此时一共"+apples.size()+"个APPLE"); if(apples.size()>=5) { System.out.println(name+"阻塞"); wait(); } notify(); apples.push(apple); System.out.println(name+"已经生产了"+apple); } public void run() { for(int i=0;i<10;i++) { try { produce("苹果"+i); } catch (Exception e) { e.printStackTrace(); } } } } class Consumer1 implements Runnable { String name; Stack<String> apples; public Consumer1(String name,Stack<String> apples) { this.name=name; this.apples=apples; } public synchronized void consume() throws Exception { // System.out.println("消费者 此时一共"+apples.size()+"个APPLE"); if(apples.size()==0) { System.out.println(name+"阻塞"); wait(); } notify(); String apple=apples.pop(); System.out.println(name+"已经消费了"+apple); } public void run() { for(int i=0;i<10;i++) { try { consume(); } catch (Exception e) { e.printStackTrace(); } } } }
结果修改后,如下
/** * 项目名称: * 文件说明: * 主要特点:生产者消费者模式 * 版本号:1.0 * 制作人:lcx * 创建时间:2013-12-3 **/ package treadgame; import java.util.Stack; /** * @author lcx * */ public class Producer_Consumer2 { public static void main(String[] args) { Resturant res=new Resturant(); Thread td1=new Thread(new Producer2(res)); // Thread td2=new Thread(new Producer("生产者2",apples)); // Thread td3=new Thread(new Producer("生产者3",apples)); Thread td4=new Thread(new Consumer2(res)); td4.start(); td1.start(); // td2.start(); // td3.start(); } } class Resturant { Stack<String> apples=new Stack<String>(); public synchronized void produce(String apple) throws Exception { // System.out.println("生产者 此时一共"+apples.size()+"个APPLE"); if(apples.size()>=5) { System.out.println("生产阻塞"); wait(); } notify(); apples.push(apple); System.out.println("已经生产了"+apple); } public synchronized void consume() throws Exception { // System.out.println("消费者 此时一共"+apples.size()+"个APPLE"); if(apples.size()==0) { System.out.println("消费阻塞"); wait(); } notify(); String apple=apples.pop(); System.out.println("已经消费了"+apple); } } class Producer2 implements Runnable { Resturant res; public Producer2(Resturant res) { this.res=res; } public void run() { for(int i=1;i<=10;i++) { try { res.produce("苹果"+i); } catch (Exception e) { e.printStackTrace(); } } } } class Consumer2 implements Runnable { Resturant res; Stack<String> apples; public Consumer2( Resturant res) { this.res=res; } public void run() { for(int i=1;i<=10;i++) { try { res.consume(); } catch (Exception e) { e.printStackTrace(); } } } }
问题3 若produce与consume方法都不是同步方法,会出现什么问题?
会出现IllegalMonitorStateException异常,因为wait必须在同步代码块中。
总结:
就我现在的经验看来,分析多线程问题,应该分析的是资源,而不是线程。因为线程的执行是由他们与资源的关系所决定的。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u011680348/article/details/47444723