weiqiang_java 2019-09-24 11:37 采纳率: 50%
浏览 398
已采纳

java 并发基础 notify()与notifyAll() 的理解

代码来自java 编程思想第4版 21章

  • 代码1
//: concurrency/NotifyVsNotifyAll.java
package concurrency; /* Added by Eclipse.py */

import java.util.concurrent.*;
import java.util.*;

class Blocker {
    synchronized void waitingCall() {
        try {
            while (!Thread.interrupted()) {
                wait();
                System.out.print(Thread.currentThread() + " ");
            }
        } catch (InterruptedException e) {
            // OK to exit this way
        }
    }

    synchronized void prod() {
        notify();                       
    }

    synchronized void prodAll() {
        notifyAll();
    }
}

class Task implements Runnable {
    static Blocker blocker = new Blocker();

    public void run() {
        blocker.waitingCall();
    }
}

class Task2 implements Runnable {
    // A separate Blocker object:
    static Blocker blocker = new Blocker();

    public void run() {
        blocker.waitingCall();
    }
}

public class NotifyVsNotifyAll {
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++)
            exec.execute(new Task());
        exec.execute(new Task2());
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            boolean prod = true;

            public void run() {
                if (prod) {
                    System.out.print("\nnotify() ");
                    Task.blocker.prod();
                    prod = false;
                } else {
                    System.out.print("\nnotifyAll() ");
                    Task.blocker.prodAll();
                    prod = true;
                }
            }
        }, 400, 400); // Run every .4 second
        TimeUnit.SECONDS.sleep(5); // Run for a while...
        timer.cancel();
        System.out.println("\nTimer canceled");
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.print("Task2.blocker.prodAll() ");
        Task2.blocker.prodAll();
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println("\nShutting down");
        exec.shutdownNow(); // Interrupt all tasks
    }
} /*
     * Output: (Sample) notify() Thread[pool-1-thread-1,5,main] notifyAll()
     * Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-5,5,main]
     * Thread[pool-1-thread-4,5,main] Thread[pool-1-thread-3,5,main]
     * Thread[pool-1-thread-2,5,main] notify() Thread[pool-1-thread-1,5,main]
     * notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-2,5,main]
     * Thread[pool-1-thread-3,5,main] Thread[pool-1-thread-4,5,main]
     * Thread[pool-1-thread-5,5,main] notify() Thread[pool-1-thread-1,5,main]
     * notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-5,5,main]
     * Thread[pool-1-thread-4,5,main] Thread[pool-1-thread-3,5,main]
     * Thread[pool-1-thread-2,5,main] notify() Thread[pool-1-thread-1,5,main]
     * notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-2,5,main]
     * Thread[pool-1-thread-3,5,main] Thread[pool-1-thread-4,5,main]
     * Thread[pool-1-thread-5,5,main] notify() Thread[pool-1-thread-1,5,main]
     * notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-5,5,main]
     * Thread[pool-1-thread-4,5,main] Thread[pool-1-thread-3,5,main]
     * Thread[pool-1-thread-2,5,main] notify() Thread[pool-1-thread-1,5,main]
     * notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread-2,5,main]
     * Thread[pool-1-thread-3,5,main] Thread[pool-1-thread-4,5,main]
     * Thread[pool-1-thread-5,5,main] Timer canceled Task2.blocker.prodAll()
     * Thread[pool-1-thread-6,5,main] Shutting down
     */// :~

  • 代码2

    //: concurrency/Restaurant.java
    package concurrency; /* Added by Eclipse.py */
    
    // The producer-consumer approach to task cooperation.
    
    import java.util.concurrent.*;
    import static net.mindview.util.Print.*;
    
    class Meal {
    private final int orderNum;
    
    public Meal(int orderNum) {
        this.orderNum = orderNum;
    }
    
    public String toString() {
        return "Meal " + orderNum;
    }
    }
    
    class WaitPerson implements Runnable {
    private Restaurant restaurant;
    
    public WaitPerson(Restaurant r) {
        restaurant = r;
    }
    
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.meal == null)
                        wait(); // ... for the chef to produce a meal
                }
                print("Waitperson got " + restaurant.meal);
                synchronized (restaurant.chef) {
                    restaurant.meal = null;
                    restaurant.chef.notifyAll(); // Ready for another
                      //这里的notifyAll();///////////////////////
                }
            }
        } catch (InterruptedException e) {
            print("WaitPerson interrupted");
        }
    }
    }
    
    class Chef implements Runnable {
    private Restaurant restaurant;
    private int count = 0;
    
    public Chef(Restaurant r) {
        restaurant = r;
    }
    
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.meal != null)  
                        wait(); // ... for the meal to be taken
                }
                if (++count == 10) {
                    print("Out of food, closing");
                    restaurant.exec.shutdownNow();
                }
                printnb("Order up! ");
                synchronized (restaurant.waitPerson) {
                    restaurant.meal = new Meal(count);
                    restaurant.waitPerson.notifyAll();-//////////////
                }
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch (InterruptedException e) {
            print("Chef interrupted");
        }
    }
    }
    
    public class Restaurant {
    Meal meal;
    ExecutorService exec = Executors.newCachedThreadPool();
    WaitPerson waitPerson = new WaitPerson(this);
    Chef chef = new Chef(this);
    
    public Restaurant() {
        exec.execute(chef);
        exec.execute(waitPerson);
    }
    
    public static void main(String[] args) {
        new Restaurant();
    }
    } /*
     * Output: Order up! Waitperson got Meal 1 Order up! Waitperson got Meal 2 Order
     * up! Waitperson got Meal 3 Order up! Waitperson got Meal 4 Order up!
     * Waitperson got Meal 5 Order up! Waitperson got Meal 6 Order up! Waitperson
     * got Meal 7 Order up! Waitperson got Meal 8 Order up! Waitperson * got Meal 9
     * Out of food, closing WaitPerson interrupted Order up! Chef interrupted
     */// :~
    
    
  • 问题

    1. notifyAll是Object的方法 ---public final native void notifyAll();但不是静态方法

这个在代码1中,为什么没有实例对象就可以直接调用该方法

而在代码2中为什么需要 restaurant.waitPerson.notifyAll() ;如果直接改成notifyAll(); 会报错

Order up! Exception in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at concurrency.Chef.run(Restaurant.java:69)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
  1. 这2种调用的方法有什么区别
  • 写回答

4条回答 默认 最新

  • lppzyt 2019-09-24 13:16
    关注

    首先notify、notifyAll 都是唤醒wait等待的线程,能唤醒的前提是,notify、notifyAll必须与wait用的是同一把锁。
    比如代码1中Blocker 的prod和prodAll方法锁的就是this。再说区别,比如利用wait、notify、notifyAll 实现生产者、消费者。
    使用notify会出现如图片所示的问题。而notifyAll是尝试唤醒所有线程直到阻塞队列中满足执行条件就会执行。
    图片说明。再来说这个在代码1中,
    为什么没有实例对象就可以直接调用该方法?因为默认是this去调因为锁的是this。而代码二中明确了锁的对象,不能用this,否则阻塞的不是你锁住的锁,java不允许这样。另外wait会释放锁,等到唤醒会重新判断条件。这个是生产者消费者的例子https://blog.csdn.net/leel0330/article/details/80455307。
    参考这个并看图片描述,希望对你有帮助。生产者把queue放满,是假设的,即存在这种情况

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?