zoukankan      html  css  js  c++  java
  • notify()-notifyAll()-wait()-join()-yield()-sleep()

    一、wait(),notify(),notifyAll()的理解与使用

     

    这三个方法由于需要控制对对象的控制权(monitor),所以属于Object而不是属于线程。

    wait(),会把持有该对象线程的对象控制权交出去,然后处于等待状态。

    notify(),会通知某个正在等待这个对象的控制权的线程可以继续运行。

    nofifyAll(),会通知所有等待这个对象控制权的线程继续运行,如果有多个正在等待该对象控制权时,具体唤醒哪个线程,就由操作系统进行调度。

    下面我们先看一个例子:

    package com.youyou.ch1.wn;
    
    /**
     *类说明:快递实体类
     */
    public class Express {
        public final static String CITY = "ShangHai";
        private int km;/*快递运输里程数*/
        private String site;/*快递到达地点*/
    
        public Express() {
        }
    
        public Express(int km, String site) {
            this.km = km;
            this.site = site;
        }
    
        /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
        public synchronized void changeKm(){
            this.km = 101;
            notify();
            //其他的业务代码
    
        }
    
        /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
        public synchronized void changeSite(){
            this.site = "BeiJing";
            notifyAll();
        }
    
        public synchronized void waitKm(){
            while(this.km<=100) {
                try {
                    wait();
                    System.out.println("check km thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("the km is"+this.km+",I will change db.");
    
        }
    
        public synchronized void waitSite(){
            while(CITY.equals(this.site)) {
                try {
                    wait();
                    System.out.println("check site thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("the site is"+this.site+",I will call user.");
        }
    }
    package com.youyou.ch1.wn;
    
    /**
     *类说明:测试wait/notify/notifyAll
     */
    public class TestWN {
        private static Express express = new Express(0,Express.CITY);
    
        /*检查里程数变化的线程,不满足条件,线程一直等待*/
        private static class CheckKm extends Thread{
            @Override
            public void run() {
                express.waitKm();
            }
        }
    
        /*检查地点变化的线程,不满足条件,线程一直等待*/
        private static class CheckSite extends Thread{
            @Override
            public void run() {
                express.waitSite();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            for(int i=0;i<3;i++){//三个线程
                new CheckSite().start();
            }
            for(int i=0;i<3;i++){//里程数的变化
                new CheckKm().start();
            }
    
            Thread.sleep(5000);
            express.changeKm();//快递地点变化
        }
    }

    结果总结:

    1.在测试的时候,我们可以改变notify和notifyAll,看看结果是什么。结果会是完全不同的;

    2.通过改变为notify的时候,我们发现的结果,我们知道,等待的线程,会被放到 队列里面,被唤醒的时候,就不太明确是哪个了?(由于是队列,那应该就是第一个)

    我们来看另外的一个例子:

    注意:

    1.生产者,消费者必须要对同一份资源进行操作。

    2.无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)

    生产者:

    package com.currentPro.waitAndnotify;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Producer implements Runnable{
    
        private List<Integer> taskQueue = new ArrayList<Integer>();
        
        //生产的量
        private final int MAX_CAPACITY;
        
        public Producer(List<Integer> sharedQueue,int size){
            this.taskQueue = sharedQueue; 
            this.MAX_CAPACITY = size;
        }
        
        @Override
           public void run()
           {
              int counter = 1;
              while (true)
              {
                 try
                 {
                   synchronized (taskQueue)
                         {
                            while (taskQueue.size() == MAX_CAPACITY)
                            {
                               System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size());
                               taskQueue.wait();
                            }
                            Thread.sleep(1000);
                            taskQueue.add(counter);
                            System.out.println("Produced: " + counter);
                            counter++;
                            //唤醒正在等待的消费者,但是消费者是不是能获取到资源,由系统调度。
                            taskQueue.notifyAll();
                         }
                 } 
                 catch (InterruptedException ex)
                 {
                    ex.printStackTrace();
                 }
              }
           }
        
    }

    消费者:

    package com.currentPro.waitAndnotify;
    
    import java.util.List;
    
    public class Consumer implements Runnable{
    
        private final List<Integer> taskQueue ;
        
        
        public Consumer(List<Integer> sharedQueue){
            this.taskQueue = sharedQueue; 
        }
        
        @Override
           public void run()
           {
              while (true)
              {
                 try
                 {
                     synchronized (taskQueue)
                         {
                            while (taskQueue.isEmpty())
                            {
                               System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size());
                               taskQueue.wait();
                            }
                            Thread.sleep(1000);
                            int i = (Integer) taskQueue.remove(0);
                            System.out.println("Consumed: " + i);
                            taskQueue.notifyAll();
                         }
                 } catch (InterruptedException ex)
                 {
                    ex.printStackTrace();
                 }
              }
           }
    }

    测试代码:

    package com.currentPro.waitAndnotify;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
    
        
        
        public static void main(String[] args) throws InterruptedException {
            //共享资源
            List<Integer> taskQueue = new ArrayList<Integer>();
            
            int MAX_CAPACITY = 5;
            //创建生产者线程
            Thread producer = new Thread(new Producer(taskQueue,MAX_CAPACITY),"producer");
            
            //创建消费者线程
            Thread consumer = new Thread(new Consumer(taskQueue),"consumer");
            
            consumer.start();
            Thread.sleep(2000);
            producer.start();
            
        }
    }

    二、join()-方法详解

    现在我们还是认为,多个相同的线程是抢占式的,但是,我们有没有方法,让线程A,一定在线程B 之前先执行呢?

    这里的话,我们可以暂时知道有两个方法,一个是 join() , 另外一个是 CountDownLatch。

    下面我们先来讲述一下 join 方法。

    下面我们来看一个简单的例子:

    package com.youyou.ch1.demo1;
    
    public class UseJoin {
        static class JumpQueue implements Runnable{
            private Thread thread;
            public JumpQueue(Thread thread){
                this.thread = thread;
            }
    
            public void run(){
                try {
                    System.out.println(thread.getName()+" will be join before "
                            +Thread.currentThread().getName());
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" terminted.");
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread previous = Thread.currentThread();//现在是主线程
            for (int i = 0; i < 10; i++) {
                Thread thread = new Thread(new JumpQueue(previous),String.valueOf(i));
                System.out.println(previous.getName()+" jump a queue the thread:"
                        +thread.getName());
                thread.start();
                previous = thread;
            }
            Thread.sleep(2000);//让主线程休眠2秒
            System.out.println(Thread.currentThread().getName() + " terminate.");
        }
    }

    下面我们在来一个简单的总结:

    面试点

    线程在执行yield()以后持有的锁是不释放的

    sleep()方法被调用以后,持有的锁是不释放的

    调动方法之前必须要持有锁调用了wait()方法以后,锁就会被释放,当wait方法返回的时候,线程会重新持有锁

    调动方法之前必须要持有锁,调用notify()方法本身不会释放锁的

  • 相关阅读:
    atitit.ntfs ext 文件系统新特性对比
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit.跨平台预定义函数 魔术方法 魔术函数 钩子函数 api兼容性草案 v2 q216  java c# php js.docx
  • 原文地址:https://www.cnblogs.com/lys-lyy/p/10958107.html
Copyright © 2011-2022 走看看