java使用wait(),notify(),notifyAll()实现等待/通知机制

public class WaitNotify {
    static boolean flag=true;
    static Object lock=new Object();

    static class Wait implements Runnable{
        @Override
        public void run() {
            synchronized (lock){
                while(flag){
                    try{
                        System.out.println(Thread.currentThread()+" flag is true. wait " +
                                "@ "+new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    }catch (InterruptedException e){
                    }
                }
            }
            System.out.println(Thread.currentThread()+" flag is false.running " +
                    "@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));

        }
    }

    static class Notify implements Runnable{
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock. notify " +
                        "@ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                SleepUtils.second(5);
            }
            synchronized (lock){
                System.out.println(String.format(Thread.currentThread() + " hold lock again. sleep " +
                        "@" + new SimpleDateFormat("HH:mm:ss").format(new Date())));
                SleepUtils.second(5);
            }
        }
    }

    public static void main(String[] args) {
        Thread waitThread=new Thread(new Wait(),"WaitThread");
        waitThread.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        }catch (InterruptedException e){

        }
        Thread notifyThread=new Thread(new Notify(),"NotifyThread");
        notifyThread.start();
    }
}

程序执行结果:

Thread[WaitThread,5,main] flag is true. wait @ 14:41:12
Thread[NotifyThread,5,main] hold lock. notify @ 14:41:13
Thread[NotifyThread,5,main] hold lock again. sleep @14:41:18
Thread[WaitThread,5,main] flag is false.running @14:41:23

1.使用wait(),notify(),notifyAll()方法之前,要获取同一个对象的锁。

2.调用wait()方法之后,线程会从RUNABLE状态变为WAITING状态,并会释放对象锁,并会将线程移入到对象的等待队列中。

3.notify()和notifyAll()调用之后,等待的线程的wait方法并不会立马返回,需要锁空闲的时候,等待的线程获取了锁,wait()方法才会返回。

4.调用了notify()和notifyAll()方法之后,notify会将一个线程从等待队列放置到同步队列,同步队列是因为锁被占有而处于BLOCKED阶段的线程,notifyAll则是将等待队列中所有的线程都移动到同步队列,这两个方法都是将线程从WAITING状态变为BLOCKED状态。

5.从wait方法返回的条件是获得了调用对象的锁。

该程序的执行流程是首先WaitThread获取了lock,然后waitThread调用wait方法,会释放锁,并将锁移入等待队列,接着notifyThread会获取锁,调用notifyAll,但是wait()方法并没有返回,因为lock没有释放,notifyThread会睡眠5秒,这时同步队列中有两个线程要获取lock,一个是notifyThread,一个是WaitThread,结果显示是notifyThread又重新获取了锁,所以这时的wait方法依然不能返回,当notifyThread执行完了之后,释放锁,waitThread获取了锁,并且wait方法返回,waitThread执行完成。

java等待/通知经典模式

等待方:

1)获取对象锁

2)如果条件不满足,那么就调用对象的wait()方法,被通知后依然要检查条件

3)条件满足则执行相应逻辑

对应的伪代码:

synchronized(对象){
   while(条件不满足){
      对象.wait()   
   }      
   执行对应逻辑代码
}

通知方:

1)获取对象锁

2)改变条件

3)通知所有在该对象上等待的线程

对应的伪代码:

synchronized(对象){
    改变对象条件
    对象.notifyAll()   
}

 

java中的Thread.join()方法使用了等待/通知经典范式

java中的Thread.join()也算是线程通信的一种方式,表示挂起当前线程,执行子线程,等到子线程执行完成之后再返回。join()方法还提供了两个超时方法,如果子线程在规定时间没有终止,就会从join()方法中返回。

Thread.join()方法源代码:

   //join函数的超时方法   
  public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;
    
     //如果设置的超时时间小于0,抛出异常 if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
     //调用wait()的时候采用delay if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } } public final synchronized void join(long millis, int nanos) throws InterruptedException { if (millis < 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 && millis == 0)) { millis++; } join(millis); } public final void join() throws InterruptedException { join(0); }

子线程执行完成之后会调用子线程的notifyAll(),会通知所有等待在该线程对象上的方法。

posted @ 2019-03-29 15:31  小白兔云  阅读(655)  评论(0)    收藏  举报