代码来自java 编程思想第4版 21章
//: 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中,为什么没有实例对象就可以直接调用该方法
而在代码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)
首先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放满,是假设的,即存在这种情况
如果某些线程在等待某些条件触发,那当那些条件为真时,你可以用 notify 和 notifyAll 来通知那些等待中的线程重新开始运行。不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll 会通知所有等待中的线程
代码1中的notifyAll()其实就是this.notifyAll(),只是把this省略了,它泛指当前对象,它在你的Task类里被定义成了静态对象,在项目启动时就被实例化了
wait()、notify、notifyAll() 都是 Object 类的方法,它们的调用都必须是基于内置锁对象的,即必须在对应的 Object 内置锁上才能调用该对象的这些方法。
具体表现在都需要在 synchronized 代码块中调用对应内置锁对象的这些方法。
例如:synchronized (restaurant.chef) 这里同步块锁对象是 restaurant.chef ,所以必须调用 restaurant.chef 相关的 notify 或者 notifyAll 方法。