wait() notify() notifyAll()小结

<span style="color: rgb(61, 70, 77); font-family: 'Pingfang SC', STHeiti, 'Lantinghei SC', 'Open Sans', Arial, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', SimSun, sans-serif; font-size: 2.6rem; line-height: 30px; background-color: rgb(255, 255, 255);">1.wait()和notify()是如何工作的?</span>

    这两个方法不并在Thread类中,而是在Object类中.这说明任何对象都可以调用这两个方法.这两个方法的方法签名如下:

public final void wait() throws InterruptedException;
public final native void notify();

    当一个对象实例调用了wait()方法后,当前线程就会在这个对象上等待.比如,线程A中,调用了OBJECT.wait()方法,那么A线程就暂停了执行,转为等待状态,它会一直等待到其他线程调用了同一对象OBJECT.notify()方法为止.这时,这个OBJECT对象就成为两个线程之间有效的通信手段.

    如果一个线程调用了OBJECT.wait(),那么它就会进入到一个线程等待的队列当中.这个等待队列当中,可能会有多个线程,因为系统多个线程都在同时等待某一个对象.当OBJECT.notify()被调用,JVM会从这个等待队列中,随机选择一个线程来唤醒.

    要注意:上面的过程并不是公平的,不会因为你的线程优先级高,或者先进入等待队列而被优先选择,是完全随机的.

2.notify()和notifyAll()的区别

    除了notify()方法外,Object类还有一个方法是:notifyAll()方法.它和notify()的用法基本一致,但不同的是,它会唤醒线程等待队列中所有等待的线程,而不是随机选择一个.


3.wait() notify() notifyAll()的使用方法

    首先需要强调的是:这三个方法不是随便就可以调用的.它们必须包含在对应的synchronized语句块中,因为无论哪个方法都要先获得同一个目标的监视器.

/**
 * <p>wait()和notify()方法案例</p>
 * <p>
 *     wait()和notify()方法必须包含在对应的synchronized语句块当中,
 *     无论是wait()还是notify都需要首先获得目标对象的一个监视器
 * </p>
 * <p>
 *     notify()和notifyAll()方法的区别在于:
 *     <ul>
 *         <li>notify():随机唤醒一个wait()的线程</li>
 *         <li>notifyAll():唤醒全部wait()的线程</li>
 *     </ul>
 * </p>
 *
 * <pre>
 *     author      XueQi
 *     date        16/5/1
 * </pre>
 */
public class SimpleWaitNotify {
    final static Object OBJECT = new Object();

    public static class T1 implements Runnable {
        @Override
        public void run() {
            synchronized (OBJECT) {
                System.out.println(System.currentTimeMillis() + ":T1 start!");
                try {
                    System.out.println(System.currentTimeMillis() + ":T1 wait for object");
                    OBJECT.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":T1 end!");
            }
        }
    }

    public static class T2 implements Runnable {
        @Override
        public void run() {
            synchronized (OBJECT) {
                System.out.println(System.currentTimeMillis() + ":T2 start!");
                try {
                    System.out.println(System.currentTimeMillis() + ":T2 wait for object");
                    OBJECT.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":T2 end!");
            }
        }
    }

    public static class T3 implements Runnable {
        @Override
        public void run() {
            Thread.yield();
            synchronized (OBJECT) {
                System.out.println(System.currentTimeMillis() + ":T3 start! notify one thread");
                OBJECT.notify();
                System.out.println(System.currentTimeMillis() + ":T3 end!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static class T4 implements Runnable {
        @Override
        public void run() {
            Thread.yield();
            synchronized (OBJECT) {
                System.out.println(System.currentTimeMillis() + ":T4 start! notify all thread");
                OBJECT.notifyAll();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":T4 end!");
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new T1());
        Thread t2 = new Thread(new T2());
        Thread t3 = new Thread(new T3());
        Thread t4 = new Thread(new T4());

        t1.start();
        t2.start();
        t3.start();
        //t4.start();
    }
}

    当我们注释掉t4.start()时,执行main方法.我们可以看到控制台只有一个线程end,另外一个wait的线程由于监视器对象一直没有顺利获得.

    当我们注释掉t3.start(),执行main方法,可以看到所有wait的线程都被唤醒,而且是有顺序,不是同时被唤醒的.    



猜你喜欢

转载自blog.csdn.net/xq328220454/article/details/52528158