• [译]Java Thread wait, notify和notifyAll示例


    Java Thread wait, notify和notifyAll示例

    Java上的Object类定义了三个final方法用于不同线程间关于某资源上的锁状态交互,这三个方法是:wait(), notify()和notifyAll()。

    当前线程可以在任意对象上调用上述的方法,前提是当前线程是此对象的监视器(object monitors)的持有者;如果未持有该monitor而调用上述方法时会抛出java.lang.IllegalMonitorStateException。

    Wait

    Object上有三种重载的wait方法,其中之一是调用了object.wait()方法的线程会无限等待下去,直到有其他线程调用了相同对象上的notify或notifyAll方法用于唤醒其他线程;另外两个方法可以指定线程被唤醒之前的等待时间。

    notify

    notify方法用于唤醒调用了object.wait()方法的等待线程,但每次调用只能唤醒一次。被唤醒的线程会变为Runnable,进而被调度执行。如果在某个object上有多个线程在等待,一次notify调用只能唤醒其中一个。具体哪个线程被唤醒取决于操作系统的线程管理的具体实现。

    notifyAll

    notifyAll可以唤醒在相同对象上调用了wait()方法的所有线程,但哪个线程先开始执行也依赖于操作系统的实现。

    上面的方法可用于解决生产者-消费者问题,在生产者-消费者场景中,消费者线程等待从队列中消费对象,而生产者会把对象放到队列中,并通知等待线程有对象可消费。

    下面看一个在相同对象上使用了wait,notify,notifyAll方法的多线程的例子。

    Message
    定义一个普通的Java bean:Message,下面的线程将会在Message对象上调用wait和notify方法。

    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来唤醒自己并继续未完成的任务。

    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());
            }
        }
    }

    或许你已经在代码中注意到,Waiter线程通过synchronized(同步代码块)获得了Message对象上的监视器。

    Notifier
    Notifier线程处理Message对象,并调用该对象上的notify方法,用于唤醒其他等待Message对象的线程。

    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();
            }
    
        }
    }  

    同样,在Notifier线程中也通过synchronized来获取Message对象上的监视器。

    WaitNotifyTest
    下面的测试代码创建了多个Waiter和Notifier线程。

    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");
        }
    }  

    调用上面的程序,将会看到如下的输出:

    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 Notifier work done

    • notify()
      但是别激动,程序并未结束,因为上面的代码中有两个waiter线程都在等待同一个Message对象,但只有一次notify()方法调用,所以只有一个线程被唤醒,而另一个线程只能继续等待。
    • notifyAll() 如果把Notifier中的notify()注释掉,并把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 Notifier work done
    waiter waiter thread got notified at time:1356318918120
    waiter processed: notifier Notifier work done

    因为notifyAll()方法会把两个waiter线程都唤醒,并先后执行,程序结束。

    原文链接:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

  • 相关阅读:
    条件运算符 (?:)
    SVN地址修改
    dev -gridview隐藏子表标题
    继承与 Data Member(3)
    继承与 Data Member(2)
    继承与 Data Member(1)
    Data Member 的存取
    Data Member 的布局
    Data Member 的绑定
    对于 sizeof(class_name) 值的讨论(2)
  • 原文地址:https://www.cnblogs.com/enjiex/p/3662565.html
Copyright © 2020-2023  润新知