• 线程以及数据对象的wait()和notifyAll()方法


          正在运行的程序称作一个进程,一个进程可以包含多个线程,这些线程可以共享进程的资源,它们共用一块存储空间。那么,各个线程在访问同一个数据对象的同时,可能引起冲突,以生产者、消费者为例,就会出现队列中没有产品的情况下,消费者扔到队列中去拿产品,与现实世界中逻辑不相符合。使用synchronized关键字可以确保线程的安全运行。

      synchronized(obj){
    .......
      obj.wait()/notifyAll();//是数据对象而不是线程调用wait和notifyAll方法
      }

      当给一个线程(比如A线程)的run方法体内加入上述代码时,说明A线程必须首先获得该数据对象的锁,才能对这个对象进行操作。A线程拿到这个obj数据对象的锁以后,在它释放以前任何其它线程都不能够操作此对象了,之所以这样,我们可以认为其它线程没有这把锁的钥匙。A线程执行obj.wait()方法后,它将释放其所占有的对象锁,A线程进入阻塞状态,同时A也就不具有了获得obj对象所的权力,这样其它线程就可以拿到这把锁了。obj.notifyAll()可以唤醒因obj对象而阻塞的所有线程,并允许它们有获得对象所的权力,obj.notify()是唤醒因obj对象而阻塞的任意一个线程。

      下面的程序模仿生产者和消费者:  

    public class WaitAndNotify {
        private static List<Double> queue;
        public WaitAndNotify(){
            queue = new ArrayList<Double>();
        }
        
        public void begin(){
            Thread producer = new Thread(){
                public void run(){
                    while(true){
                        synchronized(queue){
                            double time = 1.0d;
                        long startTime = System.currentTimeMillis();           
                        if(System.currentTimeMillis()-startTime>=time){
                                startTime =System.currentTimeMillis();
                            for(int i=0;i<10;i++){
                                    queue.add((Math.random()*10000));
                            }
                        queue.notifyAll();
                        } 
                        }
                    }
                }
            };
            producer.start();
            
            Thread consumer = new Thread(){
                 public void run(){
                    while(true){
                        synchronized(queue){
                            while(queue.isEmpty()){
                                System.out.println("队列的长度为:"+queue.size());
                                try {
                                    queue.wait();
                                } catch (InterruptedException ex) {
                                    Logger.getLogger(WaitAndNotify.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                            double result = queue.remove(0);
                            System.out.println("成功从队列中取到数据!"+result);
                        }
                    }
                }
            };
            consumer.start();    
        }  
           
        public static void main(String[] args){
            WaitAndNotify obj = new WaitAndNotify();
            queue.add(0.1231d);
            obj.begin();
        }
    }
    View Code

      producer线程向queue中放入数据,并掉调用queue.notifyAll()来唤醒所有阻塞的线程,consumer线程从queue中取数据,当没有数据时该线程就会进入阻塞状态,等待呗唤醒。

  • 相关阅读:
    date之Hi时间的思考
    空循环比较 for foreach array_map array_walk
    ECSHOP 数据库结构说明 (适用版本v2.7.3)
    自定义写入读出文件作为存储的函数
    session 重写进入redis测试
    单独批次性任务采用MySQL定时器解决需求
    php 接收 Content-Type 是 application/json的请求数据
    centos 6.4 mysql rpm 离线安装【备忘】
    solr单机版安装与基本部署
    vim&vi在编辑的时候突然卡死,不接收输入问题的解决
  • 原文地址:https://www.cnblogs.com/yueliming/p/3257029.html
Copyright © 2020-2023  润新知