美文网首页
多线程系列05-线程等待与唤醒

多线程系列05-线程等待与唤醒

作者: Sandy_678f | 来源:发表于2019-07-22 12:31 被阅读0次

    线程的等待与唤醒
    在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
    Object类中关于等待/唤醒的API详细信息如下:

    1. notify():随机唤醒在此对象监视器上等待的单个线程。
    2. notifyAll():唤醒在此对象监视器上等待的所有线程。
    3. wait():让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
    4. wait(long timeout):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
    5. wait(long timeout, int nanos):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

    示例1:wait() 和 notify()方法

    public class ThreadA extends Thread{
    
        public ThreadA(String name){
            super(name);
        }
    
        public void run(){
            synchronized (this){
                System.out.println(Thread.currentThread().getName() + " call notify()");
                //唤醒当前的wait线程
                notify();
            }
            yield();
            System.out.println(Thread.currentThread().getName() + " is running.");
        }
    
    
        public static void main(String[] args) {
            ThreadA t1 = new ThreadA("t1");
            ThreadA t2 = new ThreadA("t2");
    
            synchronized (t1){
                try{
                    //启动线程t1,t2
                    System.out.println(Thread.currentThread().getName() + " start t1");
                    t1.start();
                    System.out.println(Thread.currentThread().getName() + " start t2");
                    t2.start();
    
                    //主线程等待t1通过notify()唤醒
                    System.out.println(Thread.currentThread().getName() + " wait()");
                    t1.wait();
    
                    System.out.println(Thread.currentThread().getName() + " continue");
    
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    运行结果:

    main start t1
    main start t2
    main wait()
    t2 call notify()
    t1 call notify()
    main continue
    t2 is running.
    t1 is running.
    

    几点说明:

    1. wait()是让“当前线程”等待
    2. wait() 相当于 wait(0)方法,表示无限等待
    3. “当前线程”在调用wait()方法时,必须拥有对象的同步锁,该线程调用完wait()方法后,释放该锁

    ==========
    示例2:wait(long timeout) 方法

    public class ThreadB extends Thread{
    
        public ThreadB(String name){
            super(name);
        }
    
        public void run(){
            System.out.println(Thread.currentThread().getName() + "  is running");
            //无限循环
            while(true)
                ;
        }
    
        public static void main(String[] args) {
            ThreadB threadB = new ThreadB("threadB");
    
            synchronized (threadB){
                try {
                    //启动线程threadB
                    System.out.println(Thread.currentThread().getName() + " start threadB");
                    threadB.start();
    
                    //主线程等待threadB通过notify(),或notifyAll(),或超过3000ms; 唤醒
                    System.out.println(Thread.currentThread().getName() + " call wait");
                    threadB.wait(3000);
    
                    System.out.println(Thread.currentThread().getName() + " continue");
                    
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
    
            }
        }
    }
    

    运行结果:

    main start threadB
    main call wait
    threadB is running
    main continue
    
    Process finished with exit code 130 (interrupted by signal 2: SIGINT)
    

    ==========
    示例3:wait() 和 notifyAll()方法

    public class NotifyAllTest {
    
        private static Object obj = new Object();
    
        static class ThreadA extends Thread{
            public  ThreadA(String name){
                super(name);
            }
    
            public void run(){
                synchronized (obj){
                    try{
                        System.out.println(Thread.currentThread().getName() + " wait");
    
                        //当前线程等待唤醒
                        obj.wait();
    
                        System.out.println(Thread.currentThread().getName() + " continue");
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
    
            ThreadA t1 = new ThreadA("t1");
            ThreadA t2 = new ThreadA("t2");
            ThreadA t3 = new ThreadA("t3");
    
            t1.start();
            t2.start();
            t3.start();
            
            try{
                System.out.println(Thread.currentThread().getName() + " sleep(3000)");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            synchronized (obj){
                //主线程唤醒全部等待线程
                System.out.println(Thread.currentThread().getName() + " notifyAll()");
                obj.notifyAll();
            }
    
        }
    
    }
    

    运行结果:

    t1 wait
    main sleep(3000)
    t3 wait
    t2 wait
    main notifyAll()
    t2 continue
    t3 continue
    t1 continue
    

    几点说明:
    负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。
    notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。

    相关文章

      网友评论

          本文标题:多线程系列05-线程等待与唤醒

          本文链接:https://www.haomeiwen.com/subject/ujhjlctx.html