java编程思想笔记-并发之线程协作(二)

notify()与notifyAll()使用条件

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方法体抛出异常后捕获并且有序的关闭

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值