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()方法本身不会释放锁的

  • 相关阅读:
    【资料整理】面向对象
    【资料整理】函数(方法)
    【资料整理】数组
    【资料整理】循环、判断、三元表达式
    【资料整理】类型转换、运算符
    【资料整理】c#基础
    线性表的链式表示和实现
    线性表
    PAT 乙级1062最简分数
    HDU 1027(全排列)
  • 原文地址:https://www.cnblogs.com/lys-lyy/p/10958107.html
Copyright © 2011-2022 走看看