六、线程之间的通信【生产者和消费者设计模式】


1、概念
它描述的是有一块缓冲区作为仓库,生产者可以将生产好的产品放入仓库,消费者可以从仓库中取走产品并消费,仓库其实是一个临界资源,生产者和消费者其实就是线程,处理这个问题的核心:保证仓库中数据的安全性【线程之间的同步,在任意时刻都只有一个线程访问仓库】

2.实现
wait():当缓冲区已满或者为空时,生产者或者消费线程将停止自己的执行,放弃锁,使得自己处于等待状态,让其他的线程执行
·是Object的方法
·调用方式:对象.wait()
·表示释放锁标记,然后在锁外面进行等待【对比sleep,sleep是抱着锁休眠的】
·等待,必须放大同步代码块中执行

notify():当生产者或者消费者向缓冲区放入或者取走一个产品的时候,向其他等待的线程发出可执行的通知,同时释放锁,使得自己处于等待状态
·是Object的方法
·调用方式:对象.notify()
·表示 唤醒 锁 标记外面等待的线程,一次只能唤醒一个

notifyAll():全部唤醒
·是Object的方法
·调用方式:对象.notifyAll()
·表示 唤醒 锁 标记外面等待的所有的线程


总结:
线程之间的通信其实就是多个线程同时访问同一份资源的情况,但是操作的动作不懂,wait()、notify()、notifyAll()都是用在同步中,因为这三个方法都需要对锁进行操作
为什么这三个方法被定义在Object中,而不是Thread类中?
因为在这些方法在操作线程时,都必须要标记他们所操作线程持有的锁,为了数据的安全性,必须保证这三个方法锁操作的是同一把锁,而锁由于可以是任意的对象,所以可以被任意对象调用的方法定义在Object中

/*

一个生产线程,一个消费线程,程序运行没有问题


2个生产线程,2个消费线程,程序出现了生产一次消费两次,或生产两次消费一次的问题

出现问题的原因:线程被唤醒后没有判断标记,直接去生产或消费导致问题的发生

         解决办法:线程被唤醒后先去判断标记,把if改成while

         
         把if改成while后,又出现了死锁:原因是当线程唤醒的是本方线程时,
         会导致所有线程进入等待状态,从而死锁

         解决死锁:把notify()改成notifyAll(),问题解决了,但是不该被唤醒的
         也被唤醒了,程序性能降低了
*/
//描述产品
class Product
{
    private String name;
    private int count=1;
    private boolean flag;

    public Product(){}
    //生产产品
    public synchronized void produce(String name)
    {
         while(flag)
         {
            try{wait();}catch(InterruptedException e){e.printStackTrace();}
         }
         this.name=name+"..."+count;
         count++;
         System.out.println(Thread.currentThread().getName()+"...生产了..."+this.name);
         flag=true;
         notifyAll();
    }
    //消费产品
    public synchronized void consume()
    {
        while(!flag)
        {
           try{wait();}catch(InterruptedException e){e.printStackTrace();}
        }
        System.out.println(Thread.currentThread().getName()+"...消费了......"+this.name);
        flag=false;
        notifyAll();
    }
}
//生产任务
class Producer implements Runnable
{
     private Product product;
     public Producer(Product product)
     {
        this.product=product;
     }

     public void run()
     {
        while(true)
         {
            product.produce("笔记本");
         }
     }
}
//消费任务
class Consumer implements Runnable
{ 
     private Product product;
     public Consumer(Product product)
     {
        this.product=product;
     }

     public void run()
     {
        while(true)
         {
            product.consume();
         }
     }
}
class Demo4 
{
    public static void main(String[] args) 
    {
        Product product = new Product();

        //生产任务
        Producer producer = new Producer(product);
        //消费任务
        Consumer consumer = new Consumer(product);

        //生产线程
        Thread t0=new Thread(producer);
        Thread t1=new Thread(producer);

        //消费线程
        Thread t2=new Thread(consumer);
        Thread t3=new Thread(consumer);

        t0.start();
        t1.start();

        t2.start();
        t3.start();

    }
}

 

posted @ 2017-08-20 10:51  又等风来  阅读(194)  评论(0编辑  收藏  举报