多线程实践-生产者消费者
来源:互联网 发布:原始元素 知乎 编辑:程序博客网 时间:2024/06/06 12:46
当多个线程操作同一个资源,但是操作的动作不同时,就会需要线程间进行通信。很著名的是生产者消费者的例子。
有一个盘子,只能放一片面包,生产者生产面包放入盘子,消费者从盘子中取走面包吃掉。
由简单开始,i+1。先看一个生产者、一个消费者。
代码如下:
public class ProducerConsumerDemo { public static void main(String[] args){ Resource r = new Resource(); new Thread(new Producer(r)).start(); new Thread(new Consumer(r)).start(); }}class Resource{ //公共资源 private String name; private int count =1; private boolean flag = false; public synchronized void set(String name){ if(flag) try{this.wait();}catch(Exception e){} this.name = name + "--" + count++; System.out.println(Thread.currentThread().getName() + "...生产者:生产了"+this.name); flag = true; notify(); } public synchronized void out(){ if(!flag) try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName() + "...消费者:消费了"+this.name); flag = false; notify(); }}class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res = res; } public void run(){ while(true){ res.set("面包"); } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res = res; } public void run(){ while(true){ res.out(); } }}
运行结果如图:
由运行结果可以看到。Thread-0和Tread-1两个线程是交替进行,生产者生产商品i,消费者就把商品i消费掉。然后生产者生产商品i+1,消费者再消费商品i+1。
本来我自己想的实现过程是这样的:对于盘子来说,它有两种状态,可以往里放面包和不可以放面包。生产者来了,如果可放,就生产一个面包,并把盘子置为不可放面包的状态,如果不可放,就什么都不操作。消费者来了,如果可放(就代表不能取),就什么都不操作,如果不可放(代表能取),就取走一个面包,并把盘子置为可放面包状态。代码如下:
class Resource{ //公共资源 private String name; private int count =1; private boolean flag = false; public synchronized void set(String name){ if(flag) { } //try{this.wait();}catch(Exception e){} else{ this.name = name + "--" + count++; System.out.println(Thread.currentThread().getName() + "...生产者:生产了"+this.name); flag = true; } //notify(); } public synchronized void out(){ if(!flag){ } //try{this.wait();}catch(Exception e){} else{ System.out.println(Thread.currentThread().getName() + "...消费者:消费了"+this.name); flag = false; } //notify(); }}
与上面的示例中代码的区别是没有使用wait()和notify()方法。一样能实现效果。看图:
不用使用wait()和notify()与使用有什么区别呢?既然它存在,肯定是有它的道理的。猜测它的优点是效率更高。用什么方法可以验证一下?尝试着加了运行时间和打印输出。如图:
(1)不用wait()/notify()
(2)用wait()/notify()
count为10000时,不使用wait()和notify()生产9999个面包需要1330ms,而使用wait()和notify()生产9999个面包只需要406ms。多次执行,每次的结果相差不大。
增加一下数量级,再比比,也很明显:6704msVS 3208ms。
(1)不用wait()/notify()(2)用wait()/notify()
计时代码增加到了main方法所在类和公共资源类下,代码如下:
public class ProducerConsumerDemo { public static long strateTime; public static void main(String[] args){ Resource r = new Resource(); strateTime = System.currentTimeMillis(); new Thread(new Producer(r)).start(); new Thread(new Consumer(r)).start(); }}class Resource{ //公共资源 public static long endTime; private String name; private int count =1; private boolean flag = false; public synchronized void set(String name){ if(flag)// {// System.out.println("无效执行");// } try{this.wait();}catch(Exception e){} else{ this.name = name + "--" + count++; if(count==100000){ endTime= System.currentTimeMillis(); System.out.println("程序运行时间:" + ( endTime - ProducerConsumerDemo.strateTime )+"ms"); } System.out.println(Thread.currentThread().getName() + "...生产者:生产了"+this.name); flag = true; } notify(); } public synchronized void out(){ if(!flag)// {// System.out.println("无效执行");// } try{this.wait();}catch(Exception e){} else{ System.out.println(Thread.currentThread().getName() + "...消费者:消费了"+this.name); flag = false; } notify(); }}
对比发现,差不多两倍的差距,效率是不一样的。是因为啥呢?
//TODO:
多线程方法汇总:
等待唤醒:wait()、notify()、notifyAll()。
waite()是把线程由运行状态置为等待状态,等待线程都存在线程池中。
notify()方法是把等待状态的线程从线程池中唤醒。通常唤醒线程池中的第一个等待的线程。
notifyAll()是把线程池中的所有等待线程都唤醒。
- 多线程实践-生产者消费者
- Java多线程(5)——生产者消费者模式实践
- 学习多线程的生产者和消费者系列的相关实践
- java多线程 消费者-生产者
- 生产者消费者问题--多线程
- 多线程之生产者-消费者
- java多线程 消费者-生产者
- java 多线程 生产者消费者
- JAVA [ 多线程 -- 生产者消费者 ]
- 多线程--生产者消费者问题
- 生产者-消费者多线程实现
- 多线程练习----生产者消费者
- 多线程生产者和消费者
- 多线程_生产者消费者
- Java 多线程-生产者、消费者
- 多线程-生产者消费者
- 多线程-生产者消费者
- 多线程---生产者与消费者
- 《机器学习实战》系列之KNN算法【一】
- TCP/IP协议详解
- hive数据仓库框架之日志分析
- 数据库中事务的四大特性和隔离级别
- codeforces838E-Convex Countour
- 多线程实践-生产者消费者
- caffe源码追踪--layer
- mysql 中的and和or
- Ubuntu 安装 搜狗输入法之最简单的方法
- 中标麒麟高级服务器6.0安装KVM
- 563. Binary Tree Tilt
- 51Nod-1188-最大公约数之和 V2
- IO流——打印流(PrintWriter和PrintStream类)
- POJ 3523 The Morning after Halloween 搜索