多线程实践-生产者消费者

来源:互联网 发布:原始元素 知乎 编辑:程序博客网 时间: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()是把线程池中的所有等待线程都唤醒。






原创粉丝点击