wait,notify,notifyAll,sleep

1、wait()方法的官方文档

public final void wait(long timeout) throws InterruptedException
导致当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或指定的时间已过

当前的线程必须拥有该对象的监视器。

此方法使当前线程(称为 T )将其放置在该对象的等待集中,然后放弃对该对象的任何和所有同步声明。 线程T将无法进行线程调度,进行休眠,直到四件事情发生:

  • 一些其他线程调用该对象的notify方法,并且线程T恰好被任意选择为被唤醒的线程。
  • 某些其他线程调用此对象的notifyAll方法。
  • 一些其他线程interrupts(中断)线程T
  • 指定的实时数量已经过去,或多或少。 然而,如果timeout为零,则不考虑实时,线程等待直到通知。

然后从该对象的等待集中删除线程T ,并重新启用线程调度。 然后它以通常的方式与其他线程竞争在对象上进行同步的权限; 一旦获得了对象的控制,其对对象的所有同步声明就恢复到现状 - 也就是在调用wait方法之后的情况。 线程T,然后从调用wait方法返回。 因此,返回wait方法后,对象和线程的同步状态 Twait方法调用的时候的状态是一样的

线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒 。 虽然这在实践中很少会发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。 换句话说,等待应该总是出现在循环中,就像这样:

synchronized (obj) {
                     while (<condition does not hold>)
                         obj.wait(timeout);
                     ... // Perform action appropriate to condition
                 }

请注意, wait方法,因为它将当前线程放入该对象的等待集,仅解锁此对象; 当前线程可以同步的任何其他对象在线程等待时保持锁定。

该方法只能由作为该对象的监视器的所有者的线程调用。

2、sleep() 和 wait() 的异同

1、相同点:一旦执行方法,都可以使得当前线程进入阻塞状态
2、不同点:
(1)两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
(2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
(3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。

3、notify的官方文档

public final void notify()
唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。 选择是任意的,并且由执行时自行决定。 线程通过调用wait方法之一等待对象的监视器。

唤醒的线程将无法继续,直到当前线程放弃此对象上的锁定为止。 唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争在该对象上进行同步; 例如,唤醒的线程在下一个锁定该对象的线程中没有特权或不足(平等的)。

该方法只能由作为该对象的监视器的所有者的线程持有这个对象的锁的线程)调用。 线程如何能获取到对象的锁:

  • 通过调用一个对象被标识为synchronized实例方法来获取该对象的锁。
  • 通过执行synochronized 代码块来获取到被synochronized所修饰的括号里面的锁
  • 对于类型为Class的对象,通过执行该类的被标识为synochronized的静态方法来获取该对象的锁。

一次只能有一个线程可以拥有一个对象的锁。

4、notifyAll的官方文档

public final void notifyAll()

唤醒正在等待对象监视器的所有线程。 线程通过调用wait方法等待对象的监视器。

唤醒的线程将无法继续,直到当前线程释放该对象上的锁。 唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争在该对象上进行同步; 例如,唤醒的线程在下一个锁定该对象的线程中不会有可靠的特权或缺点。

该方法只能由作为该对象的监视器的所有者的线程调用。

5、关于wait与notify和notifyAll 方法的总结

  • 1、当线程调用wait时,首先需要确保调用了wait方法的线程已经持有了对象的锁,当线程调用wait后,该线程就会释放掉这个对象的锁,然后进入到等待状态(wait set),它就可以等待其他线程调用相同对象的notifynotifyAll方法来使得自己被唤醒,一旦这个线程被其他线程唤醒后,该线程就会与其他线程一同开始竞争这个对象的锁(公平竞争);只有当该线程获取到了这个对象的锁后,线程才会继续往下执行
  • 2、调用wait方法的代码片段需要放在一个synchronized块或者synchronized方法中,这样才可以确保线程在调用wait方法前已经获取到了对象的锁
  • 3、当某一线程调用对象的notify方法时,它会随机唤醒该对象等待集合中的任意一个线程,某个线程被唤醒后,它就会与其他线程一同竞争对象的锁
  • 4、当某一线程调用对象的notifyAll方法时,它会唤醒该对象等待集合中的所有线程,这些线程被唤醒后,它就会与其他线程一同竞争对象的锁
  • 5、在某一时刻,只有唯一一个线程可以拥有对象的锁

6、线程通信的例子:使用两个线程打印1到100,线程1和线程2交替打印

涉及到3个方法

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
  • notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。

注意:
wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常
wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

package com.test;

class Number implements Runnable {
    private int number = 1;

    @Override
    public void run(){
        while(true){
            synchronized (this){
                notify();//等价于this.notify()
                if(number <= 100){
                    System.out.println(Thread.currentThread().getName() + ": 卖票,票号为: " + number);
                    number ++;

                    try {
                        //使用wait()方法的线程进入阻塞状态
                        wait();//等价于this.wait()
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    break;
                }
            }
        }
    }
}

public class Communication {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容