java Thread学习(线程间协作)

来源:互联网 发布:java cms系统 编辑:程序博客网 时间:2024/04/28 08:51

线程件协作

线程之间除了使用锁同步两个任务的行为外,还需要进行协作,例如任务A必须在B完成后才能执行。

wait()和notify()/notifyAll()

wait()会去等待外部信号,并且在等待时将自身挂起。等待notify()信号唤醒。
wait()挂起的时候,会释放对象锁,这导致其他的线程可以使用synchronized方法,产生改变,将被挂起的线程唤醒。

  • wait()/wait(t):使用wait将挂起线程,可以无限等待,也可以指定时间,超时后恢复执行
  • 可以通过notify()/notifyAll(),或者时间到期后

注意:

  • 这些方法都是针对于对象来说的,wait()释放对象锁,挂起当前的线程。notify()在执行完同步代码块后释放锁,然后所有wait对象锁的线程中随机唤醒一个
  • wait/notify/notifyAll都是Object中的方法。但是只能在同步控制方法或者同步块中使用。否则运行报错IIIegalMonitorStateException。
  • notify()唤醒一个线程/notifyAll()唤醒所有对象锁。notify()有可能产生死锁。所以尽量使用notifyAll()
  • 使用另一个对象唤醒自身时,需要先获取对象锁。例如

    synchronized(x) {    x.notigyAll();  }

    举例:给车打蜡+抛光,打蜡后才能抛光,抛光完成后继续打蜡

    class Car{    private boolean waxOn = false;    public synchronized void waxed() {        waxOn = true;        /**         * do something         */        notifyAll();    }    public synchronized void buffed() {        waxOn = false;        /**         * do ...         */        notifyAll();    }    public synchronized void waitForWaxing() throws InterruptedException {        while(waxOn == false) {//唤醒是随机的,所以可能依然需要wait            wait();        }    }    public synchronized void waitForBuffing() throws InterruptedException {        while(waxOn == true) {            wait();        }    }}class WaxOn implements Runnable{    private Car car;    public WaxOn(Car car) {        this.car = car;    }    public void run() {        try{            while(!Thread.interrupted()) {                System.out.println("Wax On!");                car.waxed();//先执行了一次操作,后判断???                car.waitForBuffing();            }        } catch(InterruptedException e) {            System.out.println("Exiting via interrupt");        }        System.out.println("Ending wax On task");    }}class WaxOff implements Runnable {    private Car car;    public WaxOff(Car car) {        this.car = car;    }    public void run() {        try{            while(!Thread.interrupted()) {                System.out.println("Wax Off");                car.buffed();                car.waitForWaxing();            }        } catch(InterruptedException e) {            System.out.println("Exiting via interrupt");        }        System.out.println("Ending wax Off task");    }}public class WaxOMatic {    public static void main(String[] args) throws InterruptedException {        Car car = new Car();        ExecutorService service = Executors.newCachedThreadPool();        service.execute(new WaxOn(car));        service.execute(new WaxOff(car));        TimeUnit.SECONDS.sleep(5);        service.shutdownNow();    }}

Condition对象

在java.util.concurrent类库中包含了Condition类。await()和signal()/signalAll()也可以完成协调的作用。
java
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();//通过使用一个锁来获得Condition
condition.await();
condition.signal();
condition.signalAll();

注意:

  • 每一个Lock都应该在try-finally中,保证任何情况都可以释放锁。
  • 任务使用await()或者signal()前必须进行加锁。

notify()/notifyAll()

notify()仅唤醒一个线程,可能出现死锁。举例生产者P-消费者C问题。引用自http://blog.csdn.net/tayanxunhua/article/details/20998809

第一步:P1放入一个对象到buffer中;

第二步:P2试图put一个对象,此时buf中已经有一个了,所以wait

第三步:P3试图put一个对象,仍然wait

第四步:

  • C1试图从buf中获得一个对象;
  • C2试图从buf中获得一个对象,但是挡在了get方法外面
  • C3试图从buf中获得一个对象,同样挡在了get方法外面

第五步:C1执行完get方法,执行notify,退出方法。notify唤醒了P2,但是C2在P2唤醒之前先进入了get方法,所以P2必须再次获得锁,P2被挡在了put方法的外面,C2循环检查buf大小,在buf中没有对象,所以只能wait;C3在C2之后,P2之前进入了方法,由于buf中没有对象,所以也wait;

第六步:现在,有P3,C2,C3在waiting;最后P2获得了锁,在buf中放入了一个对象,执行notify,退出put方法;

第七步:notify唤醒P3;P3检查循环条件,在buf中已经有了一个对象,所以wait;现在没有线程能够notify了,三个线程就会处于死锁状态。

生产者-消费者

饭店呢的一个示例:厨师需要做饭,服务员需要端菜。饭店包含了厨师,服务员,食物。厨师、服务员、食物都包含饭店,通过饭店操纵其他的对象。

```javaclass 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 restaurant) {        this.restaurant = restaurant;    }    public void run() {        try {            while(!Thread.interrupted()) {                synchronized (this) {                    while(restaurant.getMeal() == null) {                        wait();                    }                }                System.out.println("WaitPerson got " + restaurant.getMeal());                synchronized (restaurant.getChef()) {                    while(restaurant.getMeal() != null) {                        restaurant.setMeal(null);                        restaurant.getChef().notifyAll();                    }                }            }        } catch(InterruptedException e) {            System.out.println("WaitPerson Interrupted");        }    }}class Chef implements Runnable {    private Restaurant restaurant;    private volatile int count = 0;    public Chef(Restaurant restaurant) {        this.restaurant = restaurant;    }    public void run() {        try {            while(!Thread.interrupted()) {                synchronized(this) {                    while(restaurant.getMeal() != null) {                        wait();                    }                }                if(++count == 10) {                    System.out.println("Out of food, closing");                    restaurant.getExecutorService().shutdownNow();                }                System.out.println("Order up!");                synchronized (restaurant.getWaitPerson()) {                    restaurant.setMeal(new Meal(count));                    restaurant.getWaitPerson().notifyAll();                }                TimeUnit.MILLISECONDS.sleep(100);            }        } catch(InterruptedException e) {            System.out.println("Chef Interrupted");        }    }}public class Restaurant {    private Chef chef;    private WaitPerson waitPerson;    private Meal meal;    private ExecutorService service;    public Restaurant() {        service = Executors.newCachedThreadPool();        chef = new Chef(this);        waitPerson = new WaitPerson(this);        service.execute(chef);        service.execute(waitPerson);    }    public static void main(String[] args) {        new Restaurant();    }    public void setChef(Chef chef) {        this.chef = chef;    }    public Chef getChef() {        return chef;    }    public void setWaitPerson(WaitPerson waitPerson) {        this.waitPerson = waitPerson;    }    public WaitPerson getWaitPerson() {        return waitPerson;    }    public void setMeal(Meal meal) {        this.meal = meal;    }    public Meal getMeal() {        return meal;    }    public void setExecutorService(ExecutorService service) {        this.service = service;    }    public ExecutorService getExecutorService() {        return service;    }}```

生产者-消费者与队列

同步队列:java.util.concurrent.BlockingQueue接口提供了同步队列,如果消费者从队列中获取对象,而且队列中为空,那么线程就会被挂起。
- LinkedBlockingQueue:不限定队列大小
- ArrayBlockingQueue:需要限定队列的大小
- SynchronizedBlockingQueue:默认为1的队列

常用方法 应用 add(Obj) 放入一个Object,成功返回true,否则返回异常 offer(Obj) 放入一个Object,成功返回true,否则返回false put(Obj) 放入一个Object,成功返回true,否则挂起线程,有空间时继续 poll(Obj) 取出队首的元素,如果不能立即取出,则等待指定时间,取不到返回null take(Obj) 取出队首的元素,如果不能立即取出,挂起线程,等待存在数据后再继续
```javaclass Toast {    public enum Status { DRY, BUTTERED, JAMMED}    public Status status = Status.DRY;    public final int id;    public Toast(int id) { this.id = id; }    public void butter() { status = Status.BUTTERED; }    public void jam() { status = Status.JAMMED; }    public Status getStatus() { return status; }    public int getId() { return id; }    public String toString() {        return "Toast " + id + ": " + status;    }}class ToastQueue extends LinkedBlockingQueue<Toast> {}class Toaster implements Runnable {    private ToastQueue dryQueue;    private int count = 0;    public Toaster(ToastQueue dryQueue) {        this.dryQueue = dryQueue;    }    public void run() {        try {            while(!Thread.interrupted()) {                TimeUnit.MILLISECONDS.sleep(100);                Toast t = new Toast(++count);                System.out.println("Toaster: " + t);                dryQueue.put(t);            }        } catch(InterruptedException e) {            System.out.println("Toaster interrupted");        }    }}   class Butterer implements Runnable {    private ToastQueue dryQueue, butteredQueue;    public Butterer(ToastQueue dryQueue, ToastQueue butteredQueue) {        this.dryQueue = dryQueue;        this.butteredQueue = butteredQueue;    }    public void run() {        try {            while(!Thread.interrupted()) {                Toast t = dryQueue.take();                t.butter();                System.out.println("Butter: " + t);                butteredQueue.put(t);            }        } catch(InterruptedException e) {            System.out.println("Butterer Interrupted");        }    }}class Jammer implements Runnable {    private ToastQueue butteredQueue, finishedQueue;    public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue) {        this.butteredQueue = butteredQueue;        this.finishedQueue = finishedQueue;    }    public void run() {        try {            while(!Thread.interrupted()) {                Toast t = butteredQueue.take();                t.jam();                System.out.println("Jammer: " + t);                finishedQueue.put(t);            }        } catch(InterruptedException e) {            System.out.println("Butterer Interrupted");        }    }}public class ToastOMatic {    public static void main(String[] args) throws InterruptedException {        ToastQueue dryQueue = new ToastQueue();        ToastQueue butteredQueue = new ToastQueue();        ToastQueue finishedQueue = new ToastQueue();        ExecutorService service = Executors.newCachedThreadPool();        service.execute(new Toaster(dryQueue));        service.execute(new Butterer(dryQueue, butteredQueue));        service.execute(new Jammer(butteredQueue, finishedQueue));        TimeUnit.SECONDS.sleep(3);        service.shutdownNow();    }}```

管道输入/输出

使用PipedReader,PipedWriter创建一个管道,当PipedReader读不到数据时,管道就会自动阻塞(允许不同的任务从同一个管道中读取)

```javaclass Sender implements Runnable {    private Random rand = new Random(47);    private PipedWriter out = new PipedWriter();    public void run() {        try {            while(true) {                for(char c = 'A'; c <= 'Z'; c++) {                    out.write(c);                    TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));                }            }        } catch(IOException e) {            System.out.println("Sender write exception\n" + e);        } catch(InterruptedException e) {            System.out.println("Sender write exception\n" + e);        }    }    public PipedWriter getPipedWriter() {        return out;    }}class Receiver implements Runnable {    private PipedReader in;    public Receiver(Sender s) throws IOException {        in = new PipedReader(s.getPipedWriter());    }    public void run() {        try {            while(true) {                    System.out.println("Read: " + (char)in.read());            }        } catch (IOException e) {            System.out.println("Receiver read exception\n" + e);        }    }}public class PipedIO {    public static void main(String[] args) throws Exception {        Sender sender = new Sender();        Receiver receiver = new Receiver(sender);        ExecutorService service = Executors.newCachedThreadPool();        service.execute(sender);        service.execute(receiver);        TimeUnit.SECONDS.sleep(4);        service.shutdownNow();    }}```
1 0
原创粉丝点击