zoukankan      html  css  js  c++  java
  • 六、线程之间的通信【生产者和消费者设计模式】


    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();
    
        }
    }
  • 相关阅读:
    SVN资料库转移-----dump和load
    windows Server 2003修改远程连接限制
    oracle定时任务
    Oacle常用语句
    决策树
    Logistic回归
    Matplotlab绘图基础
    基本术语
    看懂执行并优化
    数据分析方法论
  • 原文地址:https://www.cnblogs.com/lsp-lsp/p/7344432.html
Copyright © 2011-2022 走看看