11. 生产者\消费者模式
Object中的 wait()/notify()
要点:判断条件时一定要用while()循环(虚假唤醒)
public class Shop{
public int count = 0;
public void produce(){
count++;
System.out.println(Thread.currentThread().getName()+" produce product , remain: "+count+"!");
}
public void sell(){
count--;
System.out.println(Thread.currentThread().getName()+" sell product , remain: "+count+"!");
}
public static void main(String[] args){
Shop shop = new Shop();
Factory f1 =shop.new Factory(shop);
Factory f2 = shop.new Factory(shop);
Consumer c1 =shop.new Consumer(shop);
Consumer c2 = shop.new Consumer(shop);
f1.start();
f2.start();
c1.start();
c2.start();
}
class Factory extends Thread{
private Shop shop;
Factory(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true) {
synchronized (shop) {
while (shop.count >= 10) {
try {
shop.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shop.produce();
shop.notifyAll();
}
}
}
}
class Consumer extends Thread{
private Shop shop;
Consumer(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true){
synchronized (shop) {
while (shop.count <= 0) {
try {
shop.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shop.sell();
shop.notifyAll();
}
}
}
}
}
ReentryLock,Condition实现
public class Shop{
private int count = 0;
private Lock lock = new ReentrantLock();
private Condition empty = lock.newCondition();
private Condition full = lock.newCondition();
public void produce(){
count++;
System.out.println(Thread.currentThread().getName()+" produce product , remain: "+count+"!");
}
public void sell(){
count--;
System.out.println(Thread.currentThread().getName()+" sell product , remain: "+count+"!");
}
public static void main(String[] args){
Shop shop = new Shop();
Factory f1 =shop.new Factory(shop);
Factory f2 = shop.new Factory(shop);
Consumer c1 =shop.new Consumer(shop);
Consumer c2 = shop.new Consumer(shop);
f1.start();
f2.start();
c1.start();
c2.start();
}
class Factory extends Thread{
private Shop shop;
Factory(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
try {
while (shop.count >= 10) {
try {
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shop.produce();
empty.signal();
} finally {
lock.unlock();
}
}
}
}
class Consumer extends Thread{
private Shop shop;
Consumer(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true){
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
try {
while (shop.count <= 0) {
try {
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shop.sell();
full.signal();
} finally {
lock.unlock();
}
}
}
}
}
阻塞队列实现
BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:
- 当阻塞队列为空时,从阻塞队列中取数据的操作会被阻塞。
- 当阻塞队列为满时,往阻塞队列中添加数据的操作会被阻塞。
从上可知,阻塞队列是线程安全的。
JDK中的七大阻塞队列
阻塞队列名称 | 说明 |
---|---|
ArrayBlockingQueue | 一个由数组结构组成的有界阻塞队列。 |
LinkedBlockingQueue | 一个由链表结构组成的有界阻塞队列。 |
PriorityBlockingQueue | 一个支持优先级排序的无界阻塞队列。 |
DelayQueue | 一个使用优先级队列实现的无界阻塞队列。 |
SynchronousQueue | 一个不存储元素的阻塞队列。 |
LinkedTransferQueue | 一个由链表结构组成的无界阻塞队列。 |
LinkedBlockingDeque | 一个由链表结构组成的双向阻塞队列。 |
ArrayBlockingQueue:
基于数组的阻塞队列实现,其内部维护一个定长的数组,用于存储队列元素。线程阻塞的实现是通过ReentrantLock来完成的,数据的插入与取出共用同一个锁,因此ArrayBlockingQueue并不能实现生产、消费同时进行。而且在创建ArrayBlockingQueue时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。
LinkedBlockingQueue:
基于单向链表的阻塞队列实现,在初始化LinkedBlockingQueue的时候可以指定对立的大小,也可以不指定,默认类似一个无限大小的容量(Integer.MAX_VALUE),不指队列容量大小也是会有风险的,一旦数据生产速度大于消费速度,系统内存将有可能被消耗殆尽,因此要谨慎操作。另外LinkedBlockingQueue中用于阻塞生产者、消费者的锁是两个(锁分离),因此生产与消费是可以同时进行的。
BlockingQueue接口的一些方法:
操作 | 抛异常 | 特定值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
移除 | remove(o) | poll(o) | take(o) | poll(timeout, timeunit) |
检查 | element(o) | peek(o) |
这四类方法分别对应的是:
1 . ThrowsException:如果操作不能马上进行,则抛出异常
2 . SpecialValue:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false
3 . Blocks:如果操作不能马上进行,操作会被阻塞
4 . TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false
代码实现:
public class Shop{
private int count = 0;
private BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
public void produce() {
try {
queue.put(1);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" produce product , remain: "+count+"!");
}
public void sell(){
try {
queue.take();
count--;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" sell product , remain: "+count+"!");
}
public static void main(String[] args){
Shop shop = new Shop();
Factory f1 =shop.new Factory(shop);
Factory f2 = shop.new Factory(shop);
Consumer c1 =shop.new Consumer(shop);
Consumer c2 = shop.new Consumer(shop);
f1.start();
f2.start();
c1.start();
c2.start();
}
class Factory extends Thread{
private Shop shop;
Factory(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
shop.produce();
}
}
}
class Consumer extends Thread{
private Shop shop;
Consumer(Shop shop){
this.shop=shop;
}
@Override
public void run(){
while(true){
shop.sell();
}
}
}
}