wait和notify

来源:互联网 发布:js监理工程师考试真题 编辑:程序博客网 时间:2024/06/18 14:56

jdk版本1.7

在Object类中有几个方法wait()、wait(long timeout)、wait(long timeout,int nanos)、notify()、notifyAll();

wait()方法在官方文档中的解释:

  • Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. (使当前线程等待,直到有其他的线程调用notify方法 唤醒当前线程 )
  • The current thread must own this object's monitor. (当前线程必须持有当前线程的锁)
  • This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object(当前线程调用此方法后把自己放入到等待池中,并放弃所持有的锁)

wait(long timeout)方法比wait()方法多一个参数,不同之处在于超过timeout时间后也可被唤起。另:wait()=wait(0);

wait(long timeout,int nanos)方法比wait(long timeout)更精确一些。nanos是纳秒的单位,看下源码:
public final void wait(long timeout, int nanos) throws InterruptedException {        if (timeout < 0) {            throw new IllegalArgumentException("timeout value is negative");        }        if (nanos < 0 || nanos > 999999) {            throw new IllegalArgumentException(                                "nanosecond timeout value out of range");        }        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {            timeout++;        }        wait(timeout);    }可以看到并没有真正的按纳秒计算,大于等于500000纳秒的就加了一毫米。(1毫秒(ms)=1000000纳秒(ns))

notify()方法的官方文档说明:
  • Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened.
  • The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of thewait methods. 
  • (唤醒一个等待此监视器的线程,如果有多个在等待,只唤醒其中的一个。选择是任意性的,并且是在执行时决定)
notifyAll()方法的官方文档说明:
  • Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of thewait methods.(唤起所有等待此监视器的线程)
  • The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object。(当前线程停止之前,被唤起的线程不能执行。被唤起的线程需要竞争到对象锁之后才能被执行)

上大餐,一写代码就兴奋:
代码 1 
package com.corejava.thread;import com.util.DateTimeUtil;public class TestWait implements Runnable{private String msg;public TestWait(){}public TestWait( String msg ){this.msg = msg;}public void run() {String name = Thread.currentThread().getName();synchronized (msg) { try{                System.out.println("【" + name + "】,等待被唤醒" + DateTimeUtil.formatDate2String(System.currentTimeMillis(), "yyyy-MM-dd'T'HH:mm:ssZ"));                msg.wait();                //msg.wait(1000);                //msg.wait(1000,500000);            }catch(InterruptedException e){                e.printStackTrace();            } System.out.println("【" + name + "】 被唤醒。" + DateTimeUtil.formatDate2String(System.currentTimeMillis(), "yyyy-MM-dd'T'HH:mm:ssZ"));}}}#一个实现了runable接口的类,测试wait的三个方法

简单测试下 wait的三个方法:
代码 2 
public static void main(String[] args) {new Thread(new TestWait("wait"),"测试wait").start();}#分别放开wait的三个方法#第一个的时候,程序一直等待#第二个的时候,前后打印的时间相差1秒#第三个的时候,前后相差时间2秒#还可以多测试几个方案,比如:wait(0),wait(1000,0),wait(0,0),wait(1000,499999)  对比结果

代码 3

package com.corejava.thread;import com.util.DateTimeUtil;public class TestNotify implements  Runnable{private String msg;    public TestNotify(String msg) {        this.msg = msg;    }public void run() {String name = Thread.currentThread().getName();try {            Thread.sleep(1000);            synchronized (msg) {               msg.notify();               // msg.notifyAll();               System.out.println("【"+name+"】, 唤起wait线程" +DateTimeUtil.formatDate2String(System.currentTimeMillis(), "yyyy-MM-dd'T'HH:mm:ssZ"));                          }          } catch (Exception e) {                e.printStackTrace();          }}}#实现了runable的类,用于唤醒wait的线程


测试notify 只能唤起一个等待线程
代码 4 
public static void main(String[] args) throws ClassNotFoundException, Exception {String msg = "test wait notify";TestWait w1 = new TestWait(msg);new Thread(w1,"线程-1").start();TestWait w2 = new TestWait(msg);new Thread(w2,"线程-2").start();TestNotify n1 = new TestNotify(msg);new Thread(n1,"notify-1").start();}#执行结果:【线程-1】,等待被唤醒2017-08-14T17:22:11+0800【线程-2】,等待被唤醒2017-08-14T17:22:11+0800【notify-1】, 唤起wait线程2017-08-14T17:22:12+0800【线程-1】 被唤醒。2017-08-14T17:22:12+0800  
从测试代码中可以发现,启动了两个等待线程,一个notify线程。执行结果是只有一个线程被唤醒。另一个一直在等待被唤醒。(其实程序一直没有结束,另一个线程一直在等待,执行结果没法贴出来)

测试 notifyAll()唤醒所有线程:
把 代码3的notify()注释掉,notifyAll()放开,再执行代码4,执行结果如下 :

【线程-1】,等待被唤醒2017-08-14T17:39:39+0800
【线程-2】,等待被唤醒2017-08-14T17:39:39+0800
【notify-1】, 唤起wait线程2017-08-14T17:39:40+0800
【线程-2】 被唤醒。2017-08-14T17:39:40+0800
【线程-1】 被唤醒。2017-08-14T17:39:40+0800
另:程序已经结束
可以看到两个等待线程都被唤醒了。

测试notify()唤起线程的随机性

代码 5

for (int i = 0; i < 100; i++) {//Thread.sleep(10);new Thread(new TestWait(msg),"wait 线程-"+i).start();}for (int i = 0; i < 10; i++) {new Thread(new TestNotify(msg),"notify 线程-"+i).start();}#结果:【wait 线程-0】 被唤醒。2017-08-14T17:45:22+0800【notify 线程-0】, 唤起wait线程2017-08-14T17:45:22+0800【wait 线程-73】 被唤醒。2017-08-14T17:45:22+0800【notify 线程-3】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-4】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-5】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-6】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-8】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-7】, 唤起wait线程2017-08-14T17:45:22+0800【wait 线程-94】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-95】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-96】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-97】 被唤醒。2017-08-14T17:45:22+0800【notify 线程-9】, 唤起wait线程2017-08-14T17:45:22+0800【notify 线程-2】, 唤起wait线程2017-08-14T17:45:22+0800【wait 线程-98】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-99】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-92】 被唤醒。2017-08-14T17:45:22+0800【wait 线程-93】 被唤醒。2017-08-14T17:45:22+0800

代码中开了100个等待线程,10个notify线程。看结果被唤醒的线程是随机的。


总的来说 ,线程之间通过对同一个监视器(锁)的持有和释放来通信的,所以wait和 notify要在同步块中使用。







原创粉丝点击