Java多线程中wait, notify and notifyAll的使用

本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

在Java的Object类中有三个final的方法同意线程之间进行资源对象锁的通信,他们各自是: wait(), notify() and notifyAll()。

调用这些方法的当前线程必须拥有此对象监视器。否则将会报java.lang.IllegalMonitorStateException exception异常。

wait

Object的wait方法有三个重载方法,当中一个方法wait() 是无限期(一直)等待,直到其他线程调用notify或notifyAll方法唤醒当前的线程;另外两个方法wait(long timeout) 和wait(long timeout, int nanos)同意传入 当前线程在被唤醒之前须要等待的时间,timeout为毫秒数,nanos为纳秒数。

notify

notify方法仅仅唤醒一个等待(对象的)线程并使该线程開始运行。

所以假设有多个线程等待一个对象,这种方法仅仅会唤醒当中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。

notifyAll

notifyAll 会唤醒全部等待(对象的)线程,虽然哪一个线程将会第一个处理取决于操作系统的实现。

这些方法能够使用于“生产者-消费者”问题,消费者是在队列中等待对象的线程,生产者是在队列中释放对象并通知其他线程的线程。

让我们来看一个多线程作用于同一个对象的样例。我们使用wait, notify and notifyAll方法。


通过实例来理解

Message

一个java bean类。线程将会使用它并调用wait和notify方法。

Message.java

package com.journaldev.concurrency;

public class Message {
    private String msg;

    public Message(String str){
        this.msg=str;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String str) {
        this.msg=str;
    }

}

Waiter

一个Waiter类,等待其他的线程调用notify方法以唤醒线程完毕处理。

注意等待线程必须通过加synchronized同步锁拥有Message对象的监视器。

Waiter.java

package com.journaldev.concurrency;

public class Waiter implements Runnable{

    private Message msg;

    public Waiter(Message m){
        this.msg=m;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (msg) {
            try{
                System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
                msg.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
            //process the message now
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }

}

Notifier

一个Notifier类,处理Message对象并调用notify方法唤醒等待Message对象的线程。

注意synchronized代码块被用于持有Message对象的监视器。

Notifier.java

package com.journaldev.concurrency;

public class Notifier implements Runnable {

    private Message msg;

    public Notifier(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        try {
            Thread.sleep(1000);
            synchronized (msg) {
                msg.setMsg(name+" Notifier work done");
                msg.notify();
                // msg.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

WaitNotifyTest

一个測试类,交付创建多个等待线程和一个通过线程,并启动这些线程。

WaitNotifyTest.java

package com.journaldev.concurrency;

public class WaitNotifyTest {

    public static void main(String[] args) {
        Message msg = new Message("process it");
        Waiter waiter = new Waiter(msg);
        new Thread(waiter,"waiter").start();

        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1, "waiter1").start();

        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        System.out.println("All the threads are started");
    }

}

当我们调用以上的代码时能够看到下面的输出。但并没有结束(完毕),由于有两个线程等待同一个Message对象。但notify()方法仅仅能唤醒一个线程。还有一个线程仍然在等待被唤醒。

notify()

waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifying work done

假设我们凝视掉Notifier类中的notify() 方法的调用,并打开notifyAll() 方法的调用,将会有下面的输出信息。

notifyAll()

waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifying work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifying work done

一旦notifyAll()方法唤醒全部的Waiter线程。程序将会运行完毕并退出。

posted @ 2015-12-21 20:30  mengfanrong  阅读(393)  评论(0编辑  收藏  举报