Java多线程中 wait()、notify()和notifyAll()的使用

1.wait()、notify()和notifyAll()是Object类的final方法,无法被重写。

2.某个对象要调用wait()、notify()和notifyAll()都要写在同步代码块或者同步方法里面,且当前线程必须有此对象的锁。

3.调用某个对象的wait()是使当前拥有那个对象的线程挂起,暂停执行线程后面的代码,直到被另外一个线程唤醒进入等锁池,通过JVM调度获得对象的锁后才继续执行未执行完的代码。

4.某个对象的notify()方法唤醒在此对象监视器上的某个线程,具体哪一个是由JVM决定,而notifyAll()是唤醒在此对象监视器上的全部线程。

下面通过一个例子分析:

class NumberPrint implements Runnable{  
    private int number;  
    public byte res[];  
    public static int count = 5;  
    public NumberPrint(int number, byte a[]){  
        this.number = number;  
        res = a;  
    }  
    public void run(){  
        synchronized (res){  
            while(count-- > 0){  
                try {  
                    res.notify();//唤醒等待res资源的线程,把锁交给线程(该同步锁执行完毕自动释放锁)  
                    System.out.println(" "+number);  
                    res.wait();//释放CPU控制权,释放res的锁,本线程阻塞,等待被唤醒。  
                    System.out.println("------线程"+Thread.currentThread().getName()+"获得锁,wait()后的代码继续运行:"+number);  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }//end of while  
            return;  
        }//synchronized  
          
    }  
}  
public class WaitNotify {  
    public static void main(String args[]){  
        final byte a[] = {0};//以该对象为共享资源  
        new Thread(new NumberPrint((1),a),"1").start();  
        new Thread(new NumberPrint((2),a),"2").start();  
    }  
}  

输出结果:

 1  
 2  
------线程1获得锁,wait()后的代码继续运行:1  
 1  
------线程2获得锁,wait()后的代码继续运行:2  
 2  
------线程1获得锁,wait()后的代码继续运行:1  
 1  
------线程2获得锁,wait()后的代码继续运行:2  

一般情况下线程1会先启动获得res的锁(实际上不确定),线程2启动之后进入就绪状态等待线程1释放res的锁,线程1进入循环代码,先唤醒等待res线程的资源,输出1,然后调用res.wait(),释放CPU控制权,释放res的锁,挂起线程1,等待被唤醒。

然后线程2获得了res的锁进入自己线程的循环代码,调用res.notify()唤醒了线程1,输出2后把线程2挂起,释放CPU控制权和res的锁,等待被唤醒。

线程1获得了res的锁后继续后续的循环代码,先输出-------线程1获得锁,wait()后的代码继续运行:1,再执行第二次循环,唤醒线程2,输出1,再把自己挂起,释放资源。

线程2获得了res的锁后继续自己后续的循环代码,输出-------线程2获得锁,wait()后的代码继续运行:2再执行第二此循环,唤醒线程1,输出2,再把自己挂起,释放资源。

2个线程按照上述步骤依次获得资源,相继输出后面的内容。

总结:

wait()、notify和notifyAll()这些方法必须在同步代码块或者同步方法里面使用,且必须是被加锁的对象来调用。从功能上来说wait()线程主动释放CPU控制权,主动释放对象锁,同时本线程暂停执行。直到有其它线程调用加锁对象的notify()或者notifyAll()唤醒该线程,才能继续获取对象锁,并继续执行剩下的代码。这样就提供了在线程间同步、唤醒的操作。

猜你喜欢

转载自blog.csdn.net/deronn/article/details/80445440