🍇一、提出两个问题
🥄什么是wait/notify机制?
🥢wait/notify机制用来干什么的?
🍈二、尝试回答
🥒什么是wait/notify机制
首先wait和notify都是Object类里面的native方法,为什么叫做wait/notify机制,是因为这两使用的时候都是一起用的。
🥦wait/notify机制用来干什么
一般我们说到wait/notify机制都是说用来实现线程之间的通信。
🍓三、介绍一下wait/notify
wait和notify都是Object类里面的方法
wait是用来阻塞当前线程,线程调用wait方法后会被阻塞并释放线程持有的锁
notify使用来唤醒阻塞的线程,线程调用notify方法后并不会立马释放锁,只有执行完同步方法后才会释放锁。
除了wait和notify,还有对应的wait(timeout)和notifyAll,wait(timeout)是阻塞多少时间,notifyAll是唤醒所有阻塞线程。
public final void wait() throws InterruptedException {
wait(0);
}
public final native void notify();
🍊四、提出一个问题
😔问题:wait和notify用来阻塞线程的,为什么在Object类,而不在Thread类里面?
要回答这个问题就要从wait和notify的底层实现原理说起了,首先wait和notify都是native的,是通过c来实现的,
每一个对象都会生成一个objectMonitor类对应,当调用Java对象的wait和notify方法,其实就是调用objectMonitor的wait和notify方法。
所以虽然wait和notify都是来操作线程的,但是是通过对象关联类objectMonitor来实现的,所以wait和notify都在Object类里面。
🍒五、工作流程
这里我们来梳理一下wait和notify工作的流程,关于wait和notfiy的源码可以参考
1.当有两个线程来获取锁,同时在等待队列里面竞争锁。
2.现在线程t1获取到了锁。
3.现在t1获取到了锁,在执行同步代码的过程中调用了锁对象的wait方法,线程t1就将被阻塞。
4.线程t1被放到阻塞队列并且释放锁,线程t1将编程阻塞状态。
5.线程t2获取到了锁,然后执行同步代码。
6.线程t2在执行同步代码的过程中调用了notify方法,会唤醒处于阻塞状态的t1,线程t2执行完同步代码之后才会释放锁。
7.线程t1被唤醒后重新回到等待队列、线程t2执行完同步代码之后也会回到等待队列,进行下一轮的锁竞争。
🍎六、总结
回到最开始哪个问题,wait/notify机制是来干什么的
wait/notify机制是用来通信的,并不是完全贴切,wait/notify机制并不是说线程之间直接交流的,而是用来操作线程的,通过阻塞线程和唤醒阻塞线程来切换锁的占用,线程之间没有直接的交流。
🥝七、生产者消费者模式
最后用wait/notify实现一个生产者消费者代码
😩生产者
public class Producer extends Thread {
private List<Object> objects;
private int length;
public Producer(List<Object> objects, int length) {
this.objects = objects;
this.length = length;
}
@Override
public void run() {
try {
while (true) {
synchronized (objects) {
if (objects.size() >= length) {
objects.notifyAll();
objects.wait();
} else {
Object object = new Object();
objects.add(object);
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "生产了一个商品,库存:" + objects.size());
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
😃消费者
public class Consumer extends Thread {
private List<Object> objects;
public Consumer(List<Object> objects) {
this.objects = objects;
}
@Override
public void run() {
try {
while (true) {
synchronized (objects) {
if (objects.size() == 0) {
objects.notifyAll();
} else {
objects.remove(0);
System.out.println(Thread.currentThread().getName() + " 消费了一个商品,还剩:" + objects.size());
Thread.sleep(1000);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
😈管理员
public class MainDemo {
public static void main(String[] args) {
List<Object> objects = new ArrayList<>();
int length = 10;
Producer p1 = new Producer(objects,length);
p1.setName("生产者");
p1.start();
Consumer c1 = new Consumer(objects);
c1.setName("消费者");
c1.start();
}
}