下面是一段关于生产者和消费者的代码详解
总体思路是:生产者负责往数据池里面放入数据,消费者负责从尺子里取数据,其中的尺子指的是ConCurrentBlockQueue,自己实现的同步阻塞队列
如果生产者生产的数据少,而需要消费的数据多,那么这个程序会被阻塞,可以调节producerCount和ConsumerCount的数量检查同步容器的阻塞情况
代码有详细的注释
package com.lyzx.concurrent.day01;
import java.util.LinkedList;
import java.util.Queue;
/**
* 同步阻塞队列的实现,实现3个方法:
* get-获取一个值
* put-放入一个值
* size-获取当前容器中元素的个数
* @param <T>
*/
public class ConCurrentBlockQueue<T>{
private Queue<T> q = new LinkedList<>();
private int count = 0;
private int MAX = 20;
/**
* 需要注意的
* 点1:使用while而不是用if
* >> 当线程A获取锁正在执行count==0后,发现count==0为true
* >> 则进入等待,此时线程B也执行相同的操作后进入等待,当线程A再次
* >> 获取锁之后就出了if判读直接往后走count-- ,count就等于-1了
* >> 而使用while后,从wait中醒来在判断一次条件是否成立,如果成立则
* >> 继续等待,从而解决了这个问题
* 点2:this.notifyAll();
* 这是一个同步的阻塞的队列,注意是阻塞的,当元素个数为0时,可能有两个
* 线程在等待获取元素,当放入一个元素时应该很快被取走,所以要通知在这个对象(ConCurrentBlockQueue类的实例)
* 上等待的所有线程,当然包括等待取元素的线程,让其取走元素
* @return
*/
public synchronized T get(){
while(count == 0){
try {
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
count--;
this.notifyAll();
return q.poll();
}
public synchronized void put(T item){
while(count == MAX){
try {
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
count++;
this.notifyAll();
q.add(item);
System.out.println(Thread.currentThread().getName()+" 放入元素 "+item);
}
public synchronized int size(){
return count;
}
public static void main(String[] args) {
ConCurrentBlockQueue<String> q = new ConCurrentBlockQueue<>();
Runnable in = ()->{
for(int i=0;i<10;i++){
q.put("_"+i);
}
};
Runnable out = ()->{
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" 取出:"+q.get());
}
};
int producerCount = 5;
for(int i=0;i<producerCount ;i++){
new Thread(in,"C"+i).start();
}
int consumerCount = 10;
for(int i=0;i<consumerCount;i++){
new Thread(out,"P:"+i).start();
}
}
}