03_notify notifyAll 详解

notify

public final void notify()

唤醒正在此对象监视器上等待的单个线程。如果有任何线程正在等待这个对象,则选择其中一个线程被唤醒。选择是任意的,由实现决定。线程通过调用一个等待方法来等待对象的监视器。
被唤醒的线程将无法继续,直到当前线程释放该对象上的锁。被唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争同步该对象;例如,在成为下一个锁定此对象的线程时,被唤醒的线程没有可靠的特权或劣势。
此方法只能由该对象监视器的所有者线程调用。线程通过以下三种方式之一成为对象监视器的所有者:
①通过执行该对象的同步实例方法。
②通过执行对对象进行同步的同步语句的主体。
③对于类类型的对象,通过执行该类的同步静态方法。

public final native void notifyAll()

唤醒正在此对象监视器上等待的所有线程。线程通过调用一个wait方法来等待对象的监视器。
被唤醒的线程将无法继续,直到当前线程释放该对象上的锁。被唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争对该对象进行同步;例如,在成为下一个锁定此对象的线程时,被唤醒的线程没有可靠的特权或劣势。
此方法只能由该对象监视器的所有者线程调用。有关线程如何成为监视器所有者的描述,请参阅notify方法。

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

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

示例

public class Test {
     public synchronized void method1(){}
     public synchronized void method2(){}
}

Q: Test test = new Test(),创建了唯一对象,当某一个线程A调用了该类的method1方法(此方法并未执行完),另一个线程B是否可以调用该类的method2方法?
A:当然不可以,对于同一个对象来说,它的所有的synchronized方法锁的对象是一个东西。

Q:如果创建了两个对象,某一个线程调用了第一个对象的method1方法时(此方法并未执行完),另一个线程是否可以调用第二个对象的mehtod2方法?
A:当然可以,这两个对象各自有一把锁,这两个对象没有什么关系。

Q:修改public synchronized void method2(){}public static synchronized void method2(){}, Test test = new Test(),创建了唯一对象,当某一个线程A调用了该类的method1方法(此方法并未执行完),另一个线程B是否可以调用该类的method2方法?
A:当然可以,第一个方法锁的是当前对象,第二方法锁是当前对象所对应的class对象

题目:编写一个多线程程序,实现这样一个目标:
1.存在一个对象,该对象有一个int类型的成员变量counter,该成员变量的初始值为0。
2.创建两个线程,其中一个线程堆该对象的成员变量counter增1,另一个线程对该对象的成员变量减1.
3.输出该对象成员变量counter每次变化后的值。
4.最终输出的结果应为:1010101010...


package com.leofight.concurrency1;

public class MyObject {

    private int counter;

    public synchronized void increase(){
        if (counter != 0 ){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        counter++;

        System.out.println(counter);

        notify();
    }


    public synchronized  void decrease(){

        if (counter == 0 ){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        counter--;

        System.out.println(counter);

        notify();
    }
}



package com.leofight.concurrency1;

public class IncreaseThread extends  Thread {

    private MyObject myObject;

    public IncreaseThread(MyObject myObject){
        this.myObject = myObject;
    }

    @Override
    public void run() {
        for (int i = 0; i <30; ++i){
            try {
                Thread.sleep((long) (Math.random()*1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            myObject.increase();
        }
    }
}




package com.leofight.concurrency1;

public class DecreaseThread extends Thread {

    private MyObject myObject;

    public DecreaseThread(MyObject myObject){
        this.myObject = myObject;
    }


    @Override
    public void run() {
        for (int i = 0; i <30; ++i){
            try {
                Thread.sleep((long) (Math.random()*1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            myObject.decrease();
        }
    }
}


package com.leofight.concurrency1;

public class Client {

    public static void main(String[] args) {

        MyObject myObject = new MyObject();

       Thread increaseThread = new IncreaseThread(myObject);

       Thread decreaseThread = new DecreaseThread(myObject);

       increaseThread.start();

        decreaseThread.start();

    }
}



如果启动多个增加线程、多个减少线程,上述程序会出错,该如果修改呢?

修改代码如下,即可正常输出。

package com.leofight.concurrency1;

public class MyObject {

    private int counter;

    public synchronized void increase(){
        while (counter != 0 ){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        counter++;

        System.out.println(counter);

        notify();
    }


    public synchronized  void decrease(){

        while (counter == 0 ){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        counter--;

        System.out.println(counter);

        notify();
    }
}



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

推荐阅读更多精彩内容

  • 相关概念 面向对象的三个特征 封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象. 多态的好处 允许不同类对...
    东经315度阅读 1,940评论 0 8
  • 林炳文Evankaka原创作品。转载自http://blog.csdn.net/evankaka 本文主要讲了ja...
    ccq_inori阅读 653评论 0 4
  • 九种基本类型及封装类 switch语句后的控制表达式只能是short、char、int、long整数类型和枚举类型...
    zhazhaxin阅读 3,663评论 14 85
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 2,106评论 0 14
  • ReentrantLock 介绍 一个可重入的互斥锁,它具有与使用{synchronized}方法和语句访问的隐式...
    tomas家的小拨浪鼓阅读 4,049评论 1 4