• JAVA笔记16-生产者消费者问题


     http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html

    import java.util.*;
    
    public class ProducterConsumer{
        private LinkedList<Object> box= new LinkedList<Object>();
        private int max = 10 ;
        public void start(){
            new Producter().start();
            new Consumer().start();
        }
        private class Producter extends Thread{
            public void run(){
                while(true){
                    synchronized(box){
                        try{
                            while(box.size()==max){
                                System.out.println("满了");
                                box.wait();//因为synchronized(box),所以要一致
                            }
                            Object o = new Object();
                            if(box.add(o)){
                                System.out.println("producter add a object");                        
                            }
                            box.notify();//因为synchronized(box),所以要一致
                            Thread.sleep((int)(Math.random()*3000));
                            
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        private class Consumer extends Thread{
            public void run(){
                while(true){
                    synchronized(box){
                        try{
                            while(box.size()==0){
                                System.out.println("空了");
                                box.wait();
                            }
                            box.removeLast();
                            System.out.println("consumer use a object");
                            box.notify();
                            Thread.sleep((int)(Math.random()*3000));
                            
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                    
                }
            }
        }
    
        public static void main(String[] args){
            (new ProducterConsumer()).start();
        }
    }

     wait/notify

    通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务 后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。
    以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如:
    synchronized(obj) {while(!condition) {obj.wait();}obj.doSomething();}  

    当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
    在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
    synchronized(obj) {condition = true;obj.notify();} 

    需要注意的概念是:
    ◆调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
    ◆调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
    ◆当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
    ◆如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
    ◆obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
    ◆当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。

    1、模拟做馒头、吃馒头。

    public class ProducerConsumer{
        public static void main(String args[])    {
            SyncStack ss=new SyncStack();
            Producer p=new Producer(ss);
            Consumer c=new Consumer(ss);
            new Thread(p).start();
            new Thread(p).start();
            new Thread(p).start();
            new Thread(c).start();    
        }
    }
    //WoTou
    class WoTou{
        int id;
        WoTou(int id){
            this.id = id;
        }
        public String toString(){
            return "WoTou:"+id;
        }
    }
    //SyncStack
    class SyncStack{
        int index = 0;
        WoTou[] arrWT = new WoTou[6];
    
        public synchronized void push(WoTou wt){
            while(index == arrWT.length){//不能用if,否则发现异常时就跳出if语句了,此时还是满的
                try{
                    this.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
            this.notifyAll();
            arrWT[index] = wt;
            index++;
        }
    
        public synchronized WoTou pop(){
            while(index == 0){
                try{
                    this.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
            this.notifyAll();
            index--;
            return arrWT[index];
        }
    }
    //Producer
    class Producer implements Runnable{
        SyncStack ss = null;
        Producer (SyncStack ss){
            this.ss = ss;
        }
    
        public void run(){
            for(int i=0;i<60;i++){
                WoTou wt=new WoTou(i);
                ss.push(wt);
                System.out.println("生产了:" + wt);
                try{
                    Thread.sleep((int)(Math.random()*200));//sleep是静态方法 random()方法可获得0.0<x<1.0之间的随机数,返回double类型。
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    //Consumer
    class Consumer implements Runnable{
        SyncStack ss = null;
        Consumer (SyncStack ss){
            this.ss = ss; 
        }
    
        public void run(){
            for(int i=0;i<20;i++){
                WoTou wt = ss.pop();
                System.out.println("消费了:" + wt);
                try{
                    Thread.sleep((int)(Math.random()*2000));//sleep是静态方法
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

    wait:属于Object类。锁定当前对象的线程,只能在synchronized方法里面使用wait。抛出InterruptedException异常,所以必须try catch。一旦wait,释放锁,之后必须用notify叫醒。

    notify属于Object类中的,叫醒一个正在当前对象上wait的线程。

    注意:每个wait后跟一个notify/notifyAll。线程wait后,只能等待其他线程叫醒自己。

    比如同步方法pop中,当index==0时,消费者进入wait状态,此时只监听其他线程是否调用notify/notifyAll。如果一旦有线程调用了notify/notifyAll则此wait状态的进程被唤醒。整个程序只有push同步方法可能调用notify/notifyAll,所以当push方法上的进程运行时唤醒之前在wait状态的进程。

    2、线程知识总结:进程、线程的概念;创建和启动线程的两种方法(Runnable,Thread),sleep,join,yield,synchronized,wait,notify/notifyAll

  • 相关阅读:
    儿童文学经典
    育儿经
    彭博新闻社网站10月1日报道称,人民币1日获得了全球储备货币的地位。据认为,这个具有里程碑意义的事件将为中国债券市场注入活力,因为据预计,这会促使多达1万亿美元的资金在未来五年里流入该国债市。
    山西宗教文化漫谈(三)一五台山:四大佛山之首
    山西宗教文化漫谈(一)
    山西宗教文化漫谈(四)——云冈:东方艺术宝库
    山西宗教文化漫谈(六)--西山大佛
    nginx配置入门
    .zip/.rar打包与解压
    centos一键安装lnmp成功后无法访问ip(解决办法)
  • 原文地址:https://www.cnblogs.com/seven7seven/p/3670827.html
Copyright © 2020-2023  润新知