线程间通信(生产者消费者问题)

来源:互联网 发布:js面向对象编程案例 编辑:程序博客网 时间:2024/05/16 11:07

一、多线程通过把任务分成离散的和合乎逻辑的单元代替了事件循环程序。二、它远离了轮询。轮询通常由重复监测条件的循环实现。一旦条件成立,就要采取适当的行动。这浪费了CPU时间。举例来说,考虑经典的序列问题,当一个线程正在产生数据而另一个程序正在消费它。为使问题变得更有趣,假设数据产生器必须等待消费者完成工作才能产生新的数据。在轮询系统,消费者在等待生产者产生数据时会浪费很多CPU周期。一旦生产者完成工作,它将启动轮询,浪费更多的CPU时间等待消费者的工作结束,如此下去。很明显,这种情形不受欢迎。

为避免轮询,Java包含了通过wait( ),notify( )和notifyAll( )方法实现的一个进程间通信机制。这些方法在对象中是用final方法实现的,所以所有的类都含有它们。这三个方法仅在synchronized方法中才能被调用。

wait( ) 告知被调用的线程放弃管程进入睡眠直到其他线程进入相同管程并且调用notify( )。
       notify( ) 恢复相同对象中第一个调用 wait( ) 的线程。
       notifyAll( ) 恢复相同对象中所有调用 wait( ) 的线程。具有最高优先级的线程最先运行。

isAlive();判断程序是否活动状态(返回boolean值),不常用

join();等待线程结束,继续往下执行

start();启动线程,进入就绪状态

stop();停止(已过时)

sleep();使线程进入休眠

setpriority(); 设置优先级,(1-10)最大为10,最小为0,默认为5.(优先级只是增加获得cpu几率,不一定优先执行)

.currentThread();返回当前执行线程引用

package cn.thread.consumeandproducer.day23;public class Producer implements Runnable{BreadNum bn;public Producer(BreadNum bn){this.bn=bn;//new Thread(this).start();//this:实现Runnable的实例。}@Overridepublic void run() {int i=0;//生产者生产的面包while(true){bn.put(i++);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}


package cn.thread.consumeandproducer.day23;public class Consume implements Runnable {BreadNum bn;public Consume(BreadNum bn){//构造方法传参this.bn=bn;//new Thread(this).start();}@Overridepublic void run() {while(true){bn.getBread();try {Thread.sleep(2000);//消费面包需要2秒} catch (InterruptedException e) {e.printStackTrace();}}}}

package cn.thread.consumeandproducer.day23;/** *   线程间通讯问题 * 当生产者线程生产数据而消费者线程消费数据。 * 要求:生产者线程必须等待消费者消费完数据后才能产生新的数据。(生产者一次只生产一个数据,消费者一次消费一个数据) *  *      生产者生产数据时   - 消费者等待生产者生产数据 *      生产者数据生产完成  - 通知消费者开始消费数据 - 生产者等待消费者费数据   *  *      消费者消费数据时   - 生产者等待消费者消费数据 *      消费者数据消费完成   - 通知生产开始生产数据 - 消费者等待生产都生产数据 *       *      控制台如下:生产一个消费一个。 *      生产者生产的面包数量是:0消费者消费:0生产者生产的面包数量是:1消费者消费:1生产者生产的面包数量是:2消费者消费:2生产者生产的面包数量是:3消费者消费:3生产者生产的面包数量是:4消费者消费:4生产者生产的面包数量是:5消费者消费:5生产者生产的面包数量是:6消费者消费:6 */public class BreadNum {int data = 0;//面包数量boolean temp = false;public synchronized void put(int data){if(!temp){this.data=data;System.out.println("生产者生产的面包数量是:"+this.data);try {wait();} catch (InterruptedException e) {e.printStackTrace();}}notify();}public synchronized int getBread(){if(temp){try {wait();//消费者等待生产} catch (InterruptedException e) {e.printStackTrace();}}if(!temp){System.out.println("消费者消费:"+this.data);}notify();return data;}}

package cn.thread.consumeandproducer.day23;public class ProduceTest {public static void main(String[] args) {BreadNum bn = new BreadNum();Producer p = new Producer(bn);Consume c = new Consume(bn);/** * 构造方法中:new Thread(this).start();的写法 */Thread t1 = new Thread(p);t1.start();Thread t2 = new Thread(c);t2.start();}}

以上实现:生产一个,消费一个。再生产消费循环。

内部get( ), wait( )被调用。这使执行挂起直到Producer 告知数据已经预备好。这时,内部get( ) 被恢复执行。获取数据后,get( )调用notify( )。这告诉Producer可以向序列中输入更多数据。在put( )内,wait( )挂起执行直到Consumer取走了序列中的项目。当执行再继续,下一个数据项目被放入序列,notify( )被调用,这通知Consumer它应该移走该数据。

package cn.thread.consumeandproducertwo.day23;public class Consumer implements Runnable{Q q;public Consumer(Q q){this.q=q;new Thread(this).start();}@Overridepublic void run() {while(true){q.get();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}}

package cn.thread.consumeandproducertwo.day23;/** * 生产者 */public class Producer  implements Runnable{Q q;public Producer(Q q){this.q=q;new Thread(this).start();}@Overridepublic void run() {int i=0;while(true){Product p = new Product("面包",i++);q.put(p);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}

package cn.thread.consumeandproducertwo.day23;public class Product {String name;//产品名称int number;//产品编号public Product(String name,int number){this.name=name;this.number=number;}public String toString(){String s = "产品名称:"+this.name+"\t产品编号:"+this.number;return s;}}

package cn.thread.consumeandproducertwo.day23;/** * 定义一个能装五个产品的盒子,边生产边消费,边消费边生产。 * 盒子满时,生产者休息。盒子空时,消费者休息。 */public class Q {private Product[] boxs = new Product[5];//产品盒private int index = -1;/** * 放产品到盒子 */public synchronized void put(Product p){//if(index == boxs.length-1){//盒子装满if(boxs[4]!=null){System.out.println("生产者休息");try {wait();// 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。} catch (InterruptedException e) {e.printStackTrace();}}boxs[++index]=p;System.out.println("生产者:"+p);notify();//唤醒在此对象监视器上等待的单个线程。}/** * 从盒子取产品 */public synchronized Product get(){//if(index == -1){//盒子为空if(boxs[0]==null){System.out.println("消费者休息");try {wait();} catch (InterruptedException e) {e.printStackTrace();}}Product p = boxs[index--];System.out.println("消费者:"+p);notify();return p;}}

package cn.thread.consumeandproducertwo.day23;/**控制台如下: 生产者:产品名称:面包产品编号:0消费者:产品名称:面包产品编号:0生产者:产品名称:面包产品编号:1生产者:产品名称:面包产品编号:2生产者:产品名称:面包产品编号:3生产者:产品名称:面包产品编号:4消费者:产品名称:面包产品编号:4生产者:产品名称:面包产品编号:5生产者:产品名称:面包产品编号:6生产者休息消费者:产品名称:面包产品编号:6生产者:产品名称:面包产品编号:7生产者休息消费者:产品名称:面包产品编号:7生产者:产品名称:面包产品编号:8生产者休息 */public class Test {public static void main(String[] args){Q q = new Q();new Producer(q);new Consumer(q);}}

以上代码实现:定义一个能装五个产品的盒子,边生产边消费,边消费边生产。   盒子满时,生产者休息。盒子空时,消费者休息。



0 0
原创粉丝点击