一、生产者、消费者模型(两者之间有一个媒介传递数据)
生产者和消费者通过阻塞队列进行通讯。生产者生产完数据后不用等消费者处理,直接扔给阻塞队列,消费者直接从阻塞队列里取,阻塞队列相当于一个缓冲区。
1、wait()—痴汉方法。从运行态回阻塞态。死等,直到notify方法把它唤醒。等待线程。
wait():使线程停止运行,会释放对象锁。
三个特点:
①当前线程调用wait()方法后进行等待,并且该线程被置入锁对象的等待队列中,直到接到通知或被中断为止。
②wait()方法只能在同步方法或同步代码块中调用(必须是内建锁)。如果调用wait()时没有适当的锁,会抛出异常。
③wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
执行wait()后若要让线程继续运行,有两种方法:
①调用该对象的notify()方法唤醒等待线程。
②线程等待时调用interrupt()中断该线程。
wait(long time):如果到了预计时间还未被唤醒,线程将继续执行。
2、notify()方法—唤醒线程
①执行后,唤醒线程不会立即释放对象锁。要等待唤醒线程全部执行完毕后才释放对象锁。
②必须在同步方法或同步代码块中调用(必须是内建锁),用来唤醒等待在该对象上的线程。如果有多个线程等待,则任意挑选一个线程唤醒。
3、notifyAll()方法
唤醒所有在该对象上等待的线程。
4、线程阻塞的情况
①调用sleep()方法。主动放弃占有的CPU,不会释放对象锁。
②调用阻塞式IO方法(read()、write())。在该方法返回前,线程阻塞。
③线程试图获取一个monitor,但该monitor被其他线程所持有,导致阻塞。
④线程等待某个通知,即调用wait(),释放对象锁。
⑤调用线程suspend(),即线程挂起。容易导致死锁,已被废弃。
5、monitor的两个队列
每个monitor都有两个队列。一个称为同步队列(排队竞争对象锁),一个称为等待队列(存放所有调用该对象wait()等待的线程)。
- 同步队列中存放了因为竞争monitor失败、导致阻塞的线程。这些线程等待CPU调度再次竞争锁。
- 等待队列存放了因为调用wait()导致线程等待的线程。唤醒后进入同步队列竞争锁。