Java多线程--wait(),notify(),notifyAll()的用法

忙等待没有对运行等待线程的 CPU 进行有效的利用(而且忙等待消耗cpu过于恐怖,请慎用),除非平均等待时间非常短。否则,让等待线程进入睡眠或者非运行状态更为明智,直到它接收到它等待的信号。

Java 有一个内建的等待机制来允许线程在等待信号的时候变为非运行状态。java.lang.Object 类定义了三个方法,wait()、notify()和 notifyAll()来实现这个等待机制。

但在使用wait()、notify()和 notifyAll()必须获取该对象的锁,否则的话会抛异常IllegalMonitorStateException!

wait():沉睡当前线程。

notify():随机唤醒一个正在等待当前对象的线程,不可以指定唤醒哪一个。

notify():唤醒所有正在等待当前对象的线程。

注意(同步块):

1.当一个线程被唤醒以后,并不会立即退出wait()方法去执行接下来的代码,直到调用notify()方法的线程退出它自己的同步块以后。

2.同样的使用notifyAll()方法以后,并不是所有的线程都会立即退出wait()方法,获得该对象锁的线程一个接一个的退出。

import org.junit.Test;

import static java.lang.Thread.sleep;

public class MyWaitNotify {

    public class Monitor{

    }

    Monitor monitorObject = new Monitor();
    boolean waitSign = false;

    public void doWait(){
        synchronized (monitorObject){
            while (!waitSign)
            {
                try {
                    monitorObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void doNotify(){
        synchronized (monitorObject){
            waitSign=true;
            monitorObject.notify();
        }
    }

    public void doNotifyAll(){
        synchronized (monitorObject){
            waitSign=true;
            monitorObject.notifyAll();
        }
    }

    @Test
    public void testNotify(){

        new Thread(){
            public void run(){
                try {
                    System.out.println("线程1:启动");
                    sleep(5000);
                    System.out.println("线程1:notify;");
                    doNotify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程结束");
            }
        }.start();

        System.out.println("主线程wait");
        doWait();
        System.out.println("主线程被激活");
    }

    @Test
    public void testNotifyAll() {

        new Thread(){
            public void run(){
                try {
                    System.out.println("线程1:启动");
                    sleep(5000);
                    System.out.println("线程1:notifyAll;");
                    doNotifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1:结束");
            }
        }.start();

        new Thread(){
            public void run(){
                System.out.println("线程2:等待");
                doWait();
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程2:激活");
                System.out.println("线程2:结束");
            }
        }.start();

        System.out.println("主线程wait");
        doWait();
        System.out.println("主线程:激活");
        try {
            sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程:完成");
    }

}

MyWaitNotify类中:

1.testNotify()方法中,测试了主线程wait,子线程notify。

2.testNotifyAll()方法中,测试了主线程wait,子线程2wait,子线程1notifyAll。

注意容易发生的问题:

1.notify()方法执行在wait()方法之前,那么会造成调用wait()方法的线程永远在等待,不在醒来。

解决方法:将notify()信号通过变量存储,任何一个线程需要wait()之前必须要检测该变量,保证没有notify才能wait。

2.调用wait()等待的线程可能会出现“假唤醒”的情况,也就是在没有notify()的情况下,调用wait()的线程自动醒来。

解决方法:通过while循环检测notify()信号变量,如果notify()信号变量表示没有线程执行过notify()那说明确实是“假唤醒”,则需要继续wait()。

public void doWait(){
        synchronized (monitorObject){
            while (!waitSign)
            {
                try {
                    monitorObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

参考文档:http://wiki.jikexueyuan.com/project/java-concurrent/thread-communication.html

时间: 2025-01-05 22:05:30

Java多线程--wait(),notify(),notifyAll()的用法的相关文章

Java多线程_wait/notify/notifyAll方法

关于这三个方法,我们可以查询API得到下列解释: wait():导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法或者指定的事件用完 notify():唤醒在此对象监视器上等待的单个线程 notifyAll():唤醒在此对象监视器上等待的所有线程 我们需要注意的点(1)wait().notify/notifyAll() 方法是Object的本地final方法,无法被重写. (2)wait() 与 notify/notifyAll 方法必须在同步

[转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

在 Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线程调用,此时不需要考虑加锁的问题. 而对于对象的同步方法来说,在任意时刻有且仅有一个拥有该对象独占锁的线程能够调用它们.例如,一个同步方法是独占的.如果在线程调用某一对象的同步方法时,对象的独占锁被其他线程拥有,那么当前线程将处于阻塞状态,并添加到对象的入口队列中. 只有在调用线程拥有某个对象的独占锁时,才能

java多线程wait notify join

wait notify 几个注意点: wait 与 notify/notifyAll 方法必须在同步代码块中使用,即要先对调用对象加锁. 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态. 当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁. 从这里可以看出,notify/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中

java多线程wait,notify,countDownLatch的一些简单应用

第一次写,错的地方,希望大家指出,谢谢! wait ,notify都是Object中的方法: 1 ,他们必须配合synchronized关键字使用 2,wait方法释放锁,notify方法不释放锁 需求: 一个集合,2个线程,一个线程往集合中添加10个元素,另一个线程判断,如果集合中正好为5个元素时,就执行某段代码: 1 public class ListAdd2 { 2 3 private static List list = new ArrayList(); 4 public void ad

Java的wait(), notify()和notifyAll()使用心得(转)

本篇文章是对java的 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下wait(),notify()和notifyAll()都是java.lang.Object的方法:wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.notify():

Java的wait(), notify()和notifyAll()使用心得

本篇文章是对java的 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下. wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. notify

Java Object 对象上的wait(),notify(),notifyAll()方法理解

第一阶段理解(2017-7-27): Java 将wait(),notify(),notifyAll()方法放在Object对象上,也就是说任何一个对象都可以调用这个方法,这与”任何一个对象都有一个内置锁,可以用于线程同步“是照应的.因此,当某个线程要释放cpu争夺权,让自己进入等待状态时,调用 某个锁(对象)上的wait()方法,也就是让当前线程等待其它线程调用该锁上的notify()或notify()方法.线程间通过同步锁来实现等待与唤醒协作.简单例子: 1 package com.lyyc

Java总结篇系列:Java多线程(三)

一.一个典型的Java线程安全例子 1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Account account = new Account("123456", 1000); 5 DrawMoneyRunnable drawMoneyRunnable = new DrawMoneyRunnable(account, 700); 6 Thread myThread1 = new Thr

Java多线程(三)

本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Account account = new Account("123456", 1000); 5 DrawMoneyRunnable drawMoneyRunnable = new DrawMoneyRunnable(account,