1.使用notify()在众多等待同一个锁的任务只有一个被唤醒
2.使用notifyAll(),只会唤醒希望持有当前锁的所有线程
package com.tij.thread.cooperate;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Blocker {
synchronized void waitingCall() {
try {
while (!Thread.interrupted()) {
wait();
System.out.println(Thread.currentThread() + " ");
}
} catch (Exception e) {
System.err.println("WaitingCall Interrupted Exception !!!");
}
}
synchronized void prod() {
notify();
}
synchronized void prodAll() {
notifyAll();
}
}
class Task implements Runnable {
static Blocker blocker = new Blocker();
@Override
public void run() {
blocker.waitingCall();
}
}
class Task2 implements Runnable {
static Blocker blocker = new Blocker();
@Override
public void run() {
blocker.waitingCall();
}
}
public class NotifyVsNotifyAll {
public static void main(String[] args) throws InterruptedException {
ExecutorService exec=Executors.newCachedThreadPool();
//每个Task线程都会因为blocker而阻塞
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;
@Override
public void run() {
if (prod) {
System.out.println("\nnotify()");
Task.blocker.prod();
prod=false;
}else {
System.out.println("\nnotifyAll()");
Task.blocker.prodAll();
prod=true;
}
}
}, 400, 400);
TimeUnit.SECONDS.sleep(5);
timer.cancel();
System.out.println("\nTimer canceled ");
TimeUnit.MILLISECONDS.sleep(500);
System.out.println("Task2.blocker.prodAll()");
Task2.blocker.prodAll();
TimeUnit.MILLISECONDS.sleep(500);
System.out.println("\nShutting down");
exec.shutdownNow();
}
}
运行结果:
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
WaitingCall Interrupted Exception !!!
WaitingCall Interrupted Exception !!!
WaitingCall Interrupted Exception !!!
WaitingCall Interrupted Exception !!!
WaitingCall Interrupted Exception !!!
WaitingCall Interrupted Exception !!!
上面这个例子说明
1.notify只会唤醒一个线程,而notifyAll会唤醒所有持当前锁的线程
2.Task.blocker.prod()或者Task.blocker.prodAll()并不会唤醒挂起的Task2线程
接下来这个例子是关于饭店,招待,厨师的例子,一家饭店拥有一个厨师,一个招待,招待在送菜的时候(meal!=null)厨师不能继续烧菜(即不能将null的meal重新创建对象)
package com.tij.thread.cooperate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Meal{
private final int orderNum;
public Meal(int orderNum){
this.orderNum=orderNum;
}
@Override
public String toString() {
return "Meal-"+orderNum;
}
}
class WaitPerson implements Runnable{
private Restaurant restaurant;
public WaitPerson(Restaurant rc){
this.restaurant=rc;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
while (restaurant.meal==null) {
wait();
}
}
System.out.println("Waitperson got "+restaurant.meal);
//synchronized (this) {
synchronized (restaurant.chef) {
restaurant.meal=null;
//虽然在理论上使用notify()方法可以解决问题,但是在更复杂的任务中可能会有多个任务在特定对象锁上等待
//或者在团队协作中,有同事也使用了这个锁
restaurant.chef.notifyAll();
}
}
} catch (Exception e) {
System.err.println("WaitPerson InterruptedException ");
//e.printStackTrace();
}
}
}
class Chef implements Runnable{
private Restaurant restaurant;
private int count;
public Chef(Restaurant rc){
this.restaurant=rc;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
while (restaurant.meal!=null) {
wait();
}
}
if (++count==10) {
System.out.println("Out Of Food,Closing");
restaurant.exec.shutdownNow();
}
System.out.println("Order Up!");
synchronized (restaurant.waitPerson) {
restaurant.meal=new Meal(count);
restaurant.waitPerson.notifyAll();
}
TimeUnit.MILLISECONDS.sleep(100);
}
} catch (Exception e) {
System.err.println("Chef InterruptedException ");
//e.printStackTrace();
}
}
}
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();
}
}
1.需要再次重申的是wait()必须被包装在一个while()语句中,避免其它线程突然插足并改变条件
2.通常将run方法体放在try语句快中,在run方法体抛出异常后捕获并且有序的关闭