java多线程系列基础篇05-----线程等待与唤醒

wait(),notify(),notifyAll()等方法介绍

在Object.java中,定义了wait(),notify(),和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程,notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程

Object类中关于等待/唤醒的API详细信息如下

notify() 唤醒在此对象监视器上等待的单个线程

notifyAll()唤醒在此对象监视器上等待的所有线程

wait()   让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notify()方法或notifyAll()方法,当前线程被唤醒(进入"就绪状态")

wait(long timeout)让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notify()方法或notifyAll()方法,当前线程被唤醒(进入"就绪状态")或者超过我们指定的时间量 当前线程被唤醒(进入就绪状态)

wait(long timeout,int nanos)让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notify()方法或notifyAll()方法,当前线程被唤醒(进入"就绪状态")或者超过我们指定的时间量 或者其他线程中断当前线程 当前线程被唤醒(进入就绪状态)

2 wait()和notify()示例

package com.tuhu.filt.javadatathread;

public class ThreadA extends Thread{
    public ThreadA(String name){
        super(name);
    }
    public void run(){
        synchronized (this){
            System.out.println(
                    Thread.currentThread().getName()
                    +" call notify"
            );
            notify();
        }
    }
}
class WaitTest{
    public static void main(String[] args) {
        ThreadA t1 = new ThreadA("t1");
        synchronized (t1){
            try{
                System.out.println(
                        Thread.currentThread().getName()
                                +" start t1"
                );
                t1.start();
                /**
                 * 下面这个输出语句也是main线程调用的,调用了之后执行run方法才
                 * 出现那个t1 也就是t0
                 */
                System.out.println(
                        Thread.currentThread().getName()
                        +" wait()"
                );
                t1.wait();
                /**
                 * t1阻塞之后 又把main给唤醒了 哈哈哈
                 */
                System.out.println(
                        Thread.currentThread().getName()
                        +" continue"
                );
            }catch (InterruptedException e){
                e.printStackTrace();
            }

        }
    }
}

我们来说明下主线程和线程t1的流程

3 wait(long timeout)和notify()

下面演示wait(long timeout)在超时情况下,线程被唤醒的情况

package com.tuhu.filt.javadatathread;

public class ThreadB extends Thread {
    public ThreadB(String name){
        super(name);
    }
    public void run(){
        System.out.println(Thread.currentThread().getName()
        +" run"
        );
        while(true){
            ;
        }
    }
}
class WaitTimeoutTest{
    public static void main(String[] args) {
        ThreadB t1 = new ThreadB("t1");
        synchronized (t1){
            try{
                System.out.println(
                        Thread.currentThread().getName()
                        +" start t1"
                );
                t1.start();
                System.out.println(
                        Thread.currentThread().getName()
                        +" call wait"
                );
                t1.wait(3000);
                System.out.println(
                        Thread.currentThread().getName()
                        +" continue"
                );
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

4 wait()和notifyAll()

public class NotifyAllTest {

    private static Object obj = new Object();
    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();
        }
    }

    static class ThreadA extends Thread{

        public ThreadA(String name){
            super(name);
        }

        public void run() {
            synchronized (obj) {
                try {
                    // 打印输出结果
                    System.out.println(Thread.currentThread().getName() + " wait");

                    // 唤醒当前的wait线程
                    obj.wait();

                    // 打印输出结果
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue

结果说明
参考下面的流程图。 
(01) 主线程中新建并且启动了3个线程"t1", "t2"和"t3"。
(02) 主线程通过sleep(3000)休眠3秒。在主线程休眠3秒的过程中,我们假设"t1", "t2"和"t3"这3个线程都运行了。以"t1"为例,当它运行的时候,它会执行obj.wait()等待其它线程通过notify()或额nofityAll()来唤醒它;相同的道理,"t2"和"t3"也会等待其它线程通过nofity()或nofityAll()来唤醒它们。
(03) 主线程休眠3秒之后,接着运行。执行 obj.notifyAll() 唤醒obj上的等待线程,即唤醒"t1", "t2"和"t3"这3个线程。 紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj锁”。这样,"t1", "t2"和"t3"就可以获取“obj锁”而继续运行了!

5 为什么notify() wait()等函数定义在object而不是在Thread中

object wait() notify() 和synchronized一样 会对对象同步锁 进行操作

wait()会让当前线程进入等待状态 进入等待状态  所以线程应该释放它所持有的"同步锁",否则其他线程获取不到该"同步锁"而无法运行

释放掉同步锁之后,等待线程可以被notify()唤醒

请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。

负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。

总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。

猜你喜欢

转载自blog.csdn.net/lsm18829224913/article/details/81414956