美文网首页
03_notify notifyAll 详解

03_notify notifyAll 详解

作者: leofight | 来源:发表于2019-06-23 13:37 被阅读0次

    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();
        }
    }
    
    
    
    

    相关文章

      网友评论

          本文标题:03_notify notifyAll 详解

          本文链接:https://www.haomeiwen.com/subject/shviqctx.html