一、基本知识
- wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
- notify()方法可以随机唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知“一个”线程。
- notifyAll()方法可以使所有正在等待队列等待同一共享资源的“全部”线程从等待状态退出,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,因为这要取决于JVM虚拟机的实现
二、示例
- 创建一个MyList类,作为公共资源类
public class MyList {
/**
* 必须添加volatile修饰符,不然在线程中会一直取私有堆栈的值,公共堆栈的值改变后取不到
*/
volatile private List<String> list = new ArrayList<>();
public void addElement(){
list.add("咖啡");
}
public int getSize(){
return list.size();
}
}
- 创建MyThreadA,该线程类主要发出“通知”
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();
}
}
}
}
- 创建MyThreadB,该线程主要进行wait,等待对象的通知
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();
}
}
}
}
- 进行调用
/**
* 个人理解: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();
}
}
- 有个自定义的打印工具类PrintUtil
/**
* 打印工具类
* @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()));
}
}
- 结果
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多线程编程核心技术》