这里有新鲜出炉的 Java 设计模式,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
这篇文章主要介绍了 Java 中 Object 的 wait() notify() notifyAll() 方法使用的相关资料, 需要的朋友可以参考下
Java 中 Object 的 wait() notify() notifyAll() 方法使用
一、前言
对于并发编程而言,除了 Thread 以外,对 Object 对象的 wati 和 notify 对象也应该深入了解其用法,虽然知识点不多。
二、线程安全基本知识
首先应该记住以下基本点,先背下来也无妨:
同一时间一个锁只能被一个线程持有 调用对象的 wait() 和 notify() 前必须持有它
三、wait() 和 notify() 理解
3.1 wait() 和 notify() 方法简介
wait() 和 notify() 都是 Object 的方法,可以认为任意一个 Object 都是一种资源(或者资源的一个代表),当多个线程对一个资源进行操作时,如果线程发现这个资源还没有准备好,它就可以在这个资源上进行等待,即调用这个资源的 wait() 方法,如果有另外的线程经过某些处理觉得这个资源可用了,会调用这个这个资源的 notify() 方法,告诉等待它的线程,这个资源可以用了。
当然不使用 wait() 和 notify() 方法也是可以的,可以用 while() 死循环来判断,如下面的伪代码:
- class Resource{
- static boolean canUse=false;
- }
- while(!Resource.canUse){
- //如果不可用,死循环在这里等待
- }
- //当资源可以使用后,就会跳出循环,往下执行
这样做是可以,但是特别消耗 CPU 资源,所以建议用户使用 wait() 和 notify() 方法。
3.2 wait() 和 notify() 的价值
其实从单词意思来看就能看出来,wait 就是等待,说明这个资源没有准备好,我要等,还有这一个 wait(long timeout) ,表示我只能等待你这么长时间了,过时不候啊,而调用 notify() 的线程肯定就是对资源进行处理的,处理完进行通知。所以呢,它们就经常用在生产者和消费者模式中。任何涉及等资源到来的情景都适合用这两个方法,
3.3 为什么 wait() 和 notify() 必须和 synchronized 一起使用
当不在 synchronized 同步块中使用 wait() 和 notify() 或者调用方法的对象不是 synchronized 的同步锁就会抛异常:
- java.lang.IllegalMonitorStateException
很多人会疑惑为什么必须持有这个对象的锁才能调用对象的 wait() 和 notify() 方法呢,我也有这个疑惑,而且我认为这么做是没有必要的。首先看下面的代码:
- public class WaitTest {
- // 这是一个资源,模拟的Object
- final NoObjct resource = new NoObjct();
- public static void main(String[] args) throws Exception {
- WaitTest d = new WaitTest();
- d.test();
- }
- public void test() throws Exception {
- Runnable r = new Runnable() {
- public void run() {
- // 调用资源的模拟的wait方法,在方法内部使用synchronized
- resource.noWait();
- System.out.println('线程等待完,执行');
- }
- };
- Thread t = new Thread(r);
- t.start();
- Thread.sleep(2000);
- System.out.println('准备唤醒等待资源的线程');
- // 调用资源的模拟的notify方法,在方法内部使用synchronized
- resource.noNotify();
- }
- }
- // 因wait()和notify()是final方法,不能覆盖,所以模拟一个Object对象
- class NoObjct {
- // 模拟wait方法
- public void noWait() {
- // 这个就相当于将synchronized放到wait方法内部
- synchronized(this) {
- try {
- this.wait();
- } catch(InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- // 模拟notify方法
- public void noNotify() {
- // 这个就相当于将synchronized放到notify方法内部
- synchronized(this) {
- this.notify();
- }
- }
- }
这是一个简单的 wait() 和 notify() 例子,wait 等待,notify 唤醒。如果忽略掉模拟的 Object 会发现代码简洁了许多,否则就要每次使用 synchronized,如下代码:
- public class WaitTest {
- // 这是一个资源,模拟的Object
- final Object resource = new Object();
- public static void main(String[] args) throws Exception {
- WaitTest d = new WaitTest();
- d.test();
- }
- public void test() throws Exception {
- Runnable r = new Runnable() {
- public void run() {
- // 必须使用synchronized
- try {
- synchronized(resource) {
- resource.wait();
- }
- } catch(InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println('线程等待完,执行');
- }
- };
- Thread t = new Thread(r);
- t.start();
- Thread.sleep(2000);
- System.out.println('准备唤醒等待资源的线程');
- // 必须使用synchronized
- synchronized(resource) {
- resource.notify();
- }
- }
- }
所以呢,我觉得 wait() 和 notify() 和 synchronized 一起没有什么意义,毕竟 synchronized 用来进行代码同步的,和线程之间唤醒没有什么关系(希望有读者能给我相反的意见并说服我)。但是既然这么规定了就必须要去遵守,即必须在 synchronized 中使用 wait 和 notify,且调用方法的对象必须是同步对象。
四、何时使用 wait() 和 notify()
在上面已经说了这两个方法的其中一个价值就是用在生产者和消费者模式。但是通过使用它们来构建的生产者和消费者模型很低级而且复杂,完全可以使用 BlockingQueue 接口的实现类来构建。比如可以使用 ArrayBlockingQueue,它既能保证线程安全又能实现阻塞效果,何乐而不为呢。
除此之外就只有线程间休眠与唤醒了。
来源: http://www.phperz.com/article/17/0822/338585.html