java 生产者与消费者的几种实现方式
1 synchronized的方式
public class MyClass {
public static void main(String[] args){
final DataAssemble dataAssemble = new DataAssemble();
for(int i = 0; i < 20; i ++){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dataAssemble.productor();
}
},"生产者" + i);
thread.start();
}
for(int i = 0; i < 30; i ++){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dataAssemble.consumer();
}
},"消费者" + i);
thread.start();
}
}
}
public class DataAssemble {
private static final int size = 10;
private LinkedList<Data> datas = new LinkedList<>();
public synchronized void consumer(){
try {
while (datas.size() == 0){
System.out.println(Thread.currentThread().getName() + "仓库里没有了");
wait();
}
datas.poll();
System.out.println(Thread.currentThread().getName() +"消费者消费了data" + "and size = " + datas.size());
notify();
}catch (Exception e){
e.printStackTrace();
}
}
public synchronized void productor(){
try {
while (datas.size() == size){
System.out.println(Thread.currentThread().getName()+"仓库里数据满了");
wait();
}
datas.add(new Data());
System.out.println(Thread.currentThread().getName() + "生产者生产了data" + "and size = " + datas.size());
notify();
}catch (Exception e){
e.printStackTrace();
}
}
public static class Data{
}
}
运行结果:
生产者0生产者生产了dataand size = 1
生产者12生产者生产了dataand size = 2
生产者11生产者生产了dataand size = 3
生产者10生产者生产了dataand size = 4
生产者9生产者生产了dataand size = 5
生产者8生产者生产了dataand size = 6
生产者7生产者生产了dataand size = 7
生产者6生产者生产了dataand size = 8
生产者5生产者生产了dataand size = 9
生产者4生产者生产了dataand size = 10
生产者3仓库里数据满了
生产者2仓库里数据满了
生产者1仓库里数据满了
生产者19仓库里数据满了
生产者18仓库里数据满了
生产者17仓库里数据满了
生产者16仓库里数据满了
生产者15仓库里数据满了
生产者14仓库里数据满了
消费者2消费者消费了dataand size = 9
生产者13生产者生产了dataand size = 10
生产者2仓库里数据满了
消费者4消费者消费了dataand size = 9
消费者3消费者消费了dataand size = 8
生产者3生产者生产了dataand size = 9
消费者1消费者消费了dataand size = 8
消费者7消费者消费了dataand size = 7
消费者0消费者消费了dataand size = 6
生产者15生产者生产了dataand size = 7
消费者10消费者消费了dataand size = 6
生产者14生产者生产了dataand size = 7
生产者2生产者生产了dataand size = 8
消费者9消费者消费了dataand size = 7
消费者8消费者消费了dataand size = 6
生产者16生产者生产了dataand size = 7
生产者17生产者生产了dataand size = 8
消费者6消费者消费了dataand size = 7
生产者18生产者生产了dataand size = 8
生产者19生产者生产了dataand size = 9
消费者16消费者消费了dataand size = 8
消费者5消费者消费了dataand size = 7
生产者1生产者生产了dataand size = 8
消费者19消费者消费了dataand size = 7
消费者20消费者消费了dataand size = 6
消费者18消费者消费了dataand size = 5
消费者17消费者消费了dataand size = 4
消费者22消费者消费了dataand size = 3
消费者15消费者消费了dataand size = 2
消费者14消费者消费了dataand size = 1
消费者13消费者消费了dataand size = 0
消费者25仓库里没有了
消费者12仓库里没有了
消费者27仓库里没有了
消费者11仓库里没有了
消费者26仓库里没有了
消费者29仓库里没有了
消费者24仓库里没有了
消费者23仓库里没有了
消费者21仓库里没有了
消费者28仓库里没有了
注意这里面必须使用while循环判断,if循环判断会导致notify之后阻塞在wait的线程继续往下执行,引发BUG
while (datas.size() == 0){
System.out.println(Thread.currentThread().getName() + "仓库里没有了");
wait();
}
2 ReentrantLock实现
public class DataAssembleReLock {
private static final int size = 10;
private LinkedList<DataAssemble.Data> datas = new LinkedList<>();
private ReentrantLock lock = new ReentrantLock();
private Condition empty = lock.newCondition();
private Condition full = lock.newCondition();
public void consumer(){
try {
lock.lock();
while (datas.size() == 0){
System.out.println(Thread.currentThread().getName() + "仓库里没有了");
empty.await();
}
datas.poll();
System.out.println(Thread.currentThread().getName() +"消费者消费了data" + "and size = " + datas.size());
full.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void productor(){
try {
lock.lock();
while (datas.size() == size){
System.out.println(Thread.currentThread().getName()+"仓库里数据满了");
full.await();
}
datas.add(new DataAssemble.Data());
System.out.println(Thread.currentThread().getName() + "生产者生产了data" + "and size = " + datas.size());
empty.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static class Data{
}
}
3 阻塞队列实现
public class DataAssembleBlockQueue {
private static final int size = 10;
private BlockingQueue<Data> queue = new ArrayBlockingQueue<Data>(size);
public void consumer(){
try {
queue.take();
}catch (Exception e){
e.printStackTrace();
}
}
public void productor(){
try {
queue.put(new DataAssembleBlockQueue.Data());
}catch (Exception e){
e.printStackTrace();
}
}
public static class Data{
}
}