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

来源:互联网 发布:大华onvif协议端口 编辑:程序博客网 时间:2024/06/14 08:25

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

原创粉丝点击