Java高并发编程学习--9. 线程的wait和notify

一、wait和notify

  • wait和notify方法不是Thread特有的方法,而是Object的方法
    1. wait方法
      public final void wait() throws InterruptedException
      public final void wait(long timeout) throws InterruptedException
      public final void wait(long timeout, int nanos) throws InterruptedException
      wati的三个重载方法都将调用wait(long timeout)方法,wait等价于wait(0),0代表永不超时。
      (1) Object的wait(long timeout)方法会导致当前线程进入阻塞,直到有其他线程调用了此Object的notify或者notifyAll方法唤醒,或者阻塞时间达到timeout自动唤醒。
      (2) wait方法必须拥有该对象的monitor,也就是wait方法必须在同步方法中使用。
      (3) 当前线程执行了wait方法后,放弃对该monitor的所有权并进入与该对象关联的wait set中其他线程可以继续争抢该monitor的所有权。
    1. notify方法
      唤醒单个正在执行该对象wait方法的线程。
      如果某个线程由于执行该对象的wait方法而进入阻塞则会被唤醒,如果没有则忽略。
      被唤醒的线程需要重新获取对该对象所关联的monitor的lock才能继续执行。

二、wait和notify例子

  1. EventQueue.java
package communication;

import java.util.LinkedList;

/**
 * @ClassName EventQueue
 * @Description TODO
 * wait和notify方法不是Thread特有的方法,而是Object的方法
 * 1. wait方法
 * public final void wait() throws InterruptedException
 * public final void wait(long timeout) throws InterruptedException
 * public final void wait(long timeout, int nanos) throws InterruptedException
 * wati的三个重载方法都将调用wait(long timeout)方法,wait等价于wait(0),0代表永不超时
 * (1) Object的wait(long timeout)方法会导致当前线程进入阻塞,直到有其他线程调用了此
 * Object的notify或者notifyAll方法唤醒,或者阻塞时间达到timeout自动唤醒。
 * (2) wait方法必须拥有该对象的monitor,也就是wait方法必须在同步方法中使用。
 * (3) 当前线程执行了wait方法后,放弃对该monitor的所有权并进入与该对象关联的wait set中
 * 其他线程可以继续争抢该monitor的所有权
 * 2. notify方法
 * 唤醒单个正在执行该对象wait方法的线程
 * 如果某个线程由于执行该对象的wait方法而进入阻塞则会被唤醒,如果没有则忽略
 * 被唤醒的线程需要重新获取对该对象所关联的monitor的lock才能继续执行
 * @Author Cays
 * @Date 2019/3/13 15:54
 * @Version 1.0
 **/
public class EventQueue {
    private final int max;
    static class Event{

    }
    //队列,多线程共享资源,加锁处理
    private final LinkedList<Event> eventQueue=new LinkedList<>();
    private final static int DEFAULT_MAX_EVENT=10;
    public EventQueue(){
        this(DEFAULT_MAX_EVENT);
    }
    public EventQueue(int max){
        this.max=max;
    }
    //提交一个Event到队尾
    public void offer(Event event){
        synchronized (eventQueue){
            //多线程修改为while
            if (eventQueue.size()>=max){
                try {
                    console(" the queue is full.");
                    //如果队列满线程会阻塞,wait
                    //如果满了,等待消费者消费
                    eventQueue.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            console(" the new event is submitted");
            eventQueue.addLast(event);
            //多线程改为notifyAll()同时唤醒所有阻塞线程
            eventQueue.notify();
        }
    }
    //从队头获取数据,如果队头没有数据,工作线程阻塞
    public Event take(){
        synchronized (eventQueue){
            //多线程修改为while
            if (eventQueue.isEmpty()){
                try {
                    console(" the queue is empty.");
                    //如果满了,等待生产者生产
                    eventQueue.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            Event event=eventQueue.removeFirst();
            //多线程改为notifyAll()同时唤醒所有阻塞线程
            this.eventQueue.notify();
            console(" the event "+event+" is handled.");
            return event;
        }
    }
    private void console(String message){
        //线程调用wait方法被加入到与monitor关联的wait set中,一个
        //线程调用notify()唤醒一个线程,notifyAll()唤醒所有线程
        System.out.println(Thread.currentThread().getName()+":"+message);
    }
}

  1. EventClient.java
package communication;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName EventClient
 * @Description TODO
 * 生产者与消费者问题
 * wait和notify的注意事项:
 * 1. wait方法是可中断方法,当前线程一旦调用wait方法进入阻塞状态,其他线程可以使用
 * interrupt方法将其打断,同时interrupt标识被擦除。
 * 2. 线程执行了某个对象的wait方法之后,加入与之对应的wait set中,每一个对象的monitor
 * 都有与之关联的wait set。
 * 3. 当一个线程进入wait set后,notify方法可以将其唤醒,从wait set中弹出,同时中断wait
 * 中的线程也将被唤醒。
 * 4. 必须在同步方法中使用wait和notify方法,因为执行wait和notify的前提是必须持有同步
 * 方法的monitor的所有权。
 * 5. 同步代码的monitor必须与执行wait notify方法的对象一致,用哪个对象的monitor同步,
 * 就只能用哪个对象进行wait和notify操作。
 * @Author Cays
 * @Date 2019/3/13 21:30
 * @Version 1.0
 **/
public class EventClient {
    public static void main(String []args){
        final EventQueue eventQueue=new EventQueue();
        new Thread(()->{
            for (;;){
                eventQueue.offer(new EventQueue.Event());
            }
        },"Producer").start();
        new Thread(()->{
            for (;;){
                eventQueue.take();
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        },"Consumer").start();
    }
}

执行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39400984/article/details/89785851