线程间通信wait---notify

2020-09-21 10:31:13 浏览数 (1)

一、基本知识

  • wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
  • notify()方法可以随机唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知“一个”线程。
  • notifyAll()方法可以使所有正在等待队列等待同一共享资源的“全部”线程从等待状态退出,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,因为这要取决于JVM虚拟机的实现

二、示例

  1. 创建一个MyList类,作为公共资源类
代码语言:javascript复制
public class MyList {

    /**
     * 必须添加volatile修饰符,不然在线程中会一直取私有堆栈的值,公共堆栈的值改变后取不到
     */
    volatile private List<String> list = new ArrayList<>();

    public void addElement(){
        list.add("咖啡");

    }

    public int getSize(){
        return list.size();
    }
}
  1. 创建MyThreadA,该线程类主要发出“通知”
代码语言:javascript复制
public class MyThreadA extends Thread {

     private MyList list;

     private Object lock;

    public MyThreadA(MyList list, Object lock) {
        this.list = list;
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            try {
                for (int i = 0; i < 10; i  ) {
                    list.addElement();
                    System.out.println("已经添加了"   (i   1)   "个元素了");
                    Thread.sleep(1000);
                    if (list.getSize() == 5){
                        //通知
                        lock.notify();
                        System.out.println("已发出通知了");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 创建MyThreadB,该线程主要进行wait,等待对象的通知
代码语言:javascript复制
public class MyThreadB extends Thread {

     private MyList list;
     private Object lock;

    public MyThreadB(MyList list, Object lock) {
        this.list = list;
        this.lock = lock;
    }

    @Override
    public void run() {

        synchronized (lock){
            try {
                PrintUtil.enterPrint("wait");
                lock.wait();
                PrintUtil.leavePrint("wait");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}
  1. 进行调用
代码语言:javascript复制
/**
 * 个人理解:notify执行后发出通知,不过不会马上发出,需要当前方法执行完成之后才会发出,然后再有wait的方法接受的消息继续执行
 *
 * @Author: xjf
 * @Date: 2019/6/7 8:57
 */
public class Main {

    public static void main(String[] args) {
        Object lock = new Object();
        MyList list = new MyList();

        //先运行threadB,让其进入等待状态
        MyThreadB threadB = new MyThreadB(list,lock);
        threadB.setName("B");
        threadB.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        MyThreadA threadA = new MyThreadA(list,lock);
        threadA.setName("A");
        threadA.start();
    }
}
  1. 有个自定义的打印工具类PrintUtil
代码语言:javascript复制
/**
 * 打印工具类
 * @Author: xjf
 * @Date: 2019/6/4 8:44
 */
public class PrintUtil {

    /**
     * 进入方法时的打印
     * @param methodName
     */
    public static void enterPrint(String methodName){
        System.out.println("threadName=["   Thread.currentThread().getName()   "] enter into methodName=["  
                methodName   "]. time="   TimeUtil.convertToString(System.currentTimeMillis()));

    }

    /**
     * 离开方法时的打印
     * @param methodName
     */
    public static void leavePrint(String methodName){
        System.out.println("threadName=["   Thread.currentThread().getName()   "] leave methodName=["  
                methodName   "]. time="   TimeUtil.convertToString(System.currentTimeMillis()));
    }
}
  1. 结果
代码语言:javascript复制
threadName=[B] enter into methodName=[wait]. time=19-06-07 13:27:14
已经添加了1个元素了
已经添加了2个元素了
已经添加了3个元素了
已经添加了4个元素了
已经添加了5个元素了
已发出通知了
已经添加了6个元素了
已经添加了7个元素了
已经添加了8个元素了
已经添加了9个元素了
已经添加了10个元素了
threadName=[B] leave methodName=[wait]. time=19-06-07 13:27:25

Process finished with exit code 0

参考:《Java多线程编程核心技术》

0 人点赞