JAVA进阶之路-Object中的wait notify notifyall方法

Posted LuckyZhouStar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA进阶之路-Object中的wait notify notifyall方法相关的知识,希望对你有一定的参考价值。

概念介绍

先说两个概念:锁池和等待池锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中。
然后再来说notify和notifyAll的区别 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。

所以wait会阻塞持有该对象的线程,并且会释放锁,notify和notifyall的区别只不过是通过所有阻塞的对象线程进行竞争,还是通知一个进行竞争的区别

代码示例

package basic.thread;


import java.util.concurrent.TimeUnit;

public class WaitAndNotify 
    public static void main(String[] args) 
        Object co = new Object();
        System.out.println(co);

        for (int i = 0; i < 5; i++) 
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        

        try 
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");
            synchronized (co) 
                co.notifyAll();
            

            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");

         catch (InterruptedException e) 
            e.printStackTrace();
        
    

    static class MyThread extends Thread 
        private String name;
        private Object co;

        public MyThread(String name, Object o) 
            this.name = name;
            this.co = o;
        

        @Override
        public void run() 
            System.out.println(name + " is waiting.");
            try 
                synchronized (co) 
                    System.out.println("current name" + Thread.currentThread().getName());
                    //调用wait方法后,会释放锁,所以后续的线程也可以进入到里面
                    co.wait();
                
                System.out.println(name + " has been notified.");
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

上述代码,如果是notify的话,返回的结果是:
Thread0 is waiting.
Thread1 is waiting.
current nameThread-0
Thread2 is waiting.
current nameThread-1
Thread3 is waiting.
current nameThread-2
Thread4 is waiting.
current nameThread-3
current nameThread-4
-----Main Thread notify-----
Thread0 has been notified.
Main Thread is end.

如果改成notifyall的话,返回的结果是:
Thread0 is waiting.
current nameThread-0
Thread1 is waiting.
current nameThread-1
Thread2 is waiting.
current nameThread-2
Thread3 is waiting.
Thread4 is waiting.
current nameThread-3
current nameThread-4
-----Main Thread notify-----
Thread0 has been notified.
Thread1 has been notified.
Thread3 has been notified.
Thread2 has been notified.
Thread4 has been notified.
Main Thread is end.

以上是关于JAVA进阶之路-Object中的wait notify notifyall方法的主要内容,如果未能解决你的问题,请参考以下文章

Java 从入门到进阶之路(十八)

Java进阶多线程开发关键技术

JAVA进阶之路-java中的位操作

Java Object对象中的wait,notify,notifyAll的理解

java进阶之路-java中的ThreadPoolExecutor

Java之Object对象中的wait()和notifyAll()用法