从一个很经典也很基础的例子入手
生产者消费者模型,包含三个角色,分别是生产者,消费者,缓存,是一种经典的多线程场景下程序设计,好处是解耦,缓解生产消费两端的性能差,后面的各种消息队列其实都是这种思想发展而来
生产者
public class MsProducer implements Runnable{
private ArrayList<Integer> q ;
private Object a ;
public MsProducer(ArrayList<Integer> q, Object a) {
this.q = q;
this.a = a;
}
@Override
public void run() {
int i = 0 ;
for (;;){
synchronized (a){
if (q.size() >= 10){
try {
a.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
q.add(i++);
System.out.println("生产了一个值:" + i);
a.notify();
}
}
}
}
消费者
public class MsConsumer implements Runnable{
private ArrayList<Integer> q ;
private Object a ;
public MsConsumer(ArrayList<Integer> q, Object a) {
this.q = q;
this.a = a;
}
@Override
public void run() {
while (true){
synchronized (a){
if (q.size() <= 0){
try {
a.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int t = q.remove(0);
System.out.println("消费到一个值:" + t);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.notify();
}
}
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
ArrayList<Integer> q = new ArrayList(10);
Object a = new Object();
new Thread(new MsProducer(q,a)).start();
new Thread(new MsConsumer(q,a)).start();
}
}
wait()和notify()是Object的方法,而不属于Thread
当一个对象实例调用wait()方法之后,当前线程就会在这个对象上等待
直到其他线程调用了notify()或者notifyAll()
notify()和notifyAll()
如果有多个线程在对象的等待队列中,notify()会从队列中随机唤醒一个线程继续执行
而notifyAll()会唤醒所有等待线程,让他们竞争到锁
wait()和notify()方法的前提都是已经获取到锁
既然wait()方法阻塞线程,释放锁,那notify()如何执行,这里隐藏的信息是,当线程在调用wait()被唤醒的时候,必须先获取到锁,再继续向下执行
举一个简单的例子:
1. 消费者取得对象锁
2. 消费者调用wait()
3. 消费者释放对象锁
消费者等待对象锁 4. 生产者取得对象锁
消费者等待对象锁 5. 生产者调用notify()
消费者等待对象锁 6. 生产者释放对象锁
7.消费者重新获取对象锁
8.继续执行