您的位置:首页 > 编程语言 > Java开发

Java多线程之生产者消费者问题<三>:使用阻塞队列更优雅地解决生产者消费者问题

2016-03-17 14:18 543 查看
前一篇文章讲了如何使用java5中的重入锁和条件变量优雅地解决生产者消费者问题,本文将继续探究java并发包(concurrent),寻求更好的解决方案。

java并发包中提供了阻塞队列(BlockingQueue),查看该类的注释说明,大概翻译下:这是一个额外支持等待队列非空或等待队列可用的队列,意思就是当线程去队列取元素时,如果没有元素线程将等待,直到有可用的有元素可取;当向队列中添加元素时,判断队列是否已满,如果已满,则线程等待,直到队列可以添加元素。这样一看,阻塞队列完全可以解决生产者消费者问题。代码如下:

Consumer.javapackage CreatorAndConsumerBlock;

public class Consumer implements Runnable {
/**
* 线程资源
*/
private Plate plate;

public Consumer(Plate plate) {
this.plate = plate;
}

@Override
public void run() {
plate.getEgg();
}
}
Creator.java
package CreatorAndConsumerBlock;

/**
* 生产者
*
* @author Martin
*/
public class Creator implements Runnable {
/**
* 线程资源
*/
private Plate plate;

public Creator(Plate plate) {
this.plate = plate;
}

@Override
public void run() {
Object egg = new Object();
plate.addEgg(egg);
}
}
Plate.java
package CreatorAndConsumerBlock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 盘子,表示共享的资源
*
* @author Martin
*/
public class Plate {
/**
* 将arraylist换成阻塞队列,可见使用了阻塞队列后,代码中再也没有了lock、condition等了,完全不需要手动控制线程的等待还是唤醒了
*/
private ArrayBlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(99999);

/**
* 获取蛋
*
* @return
*/
public Object getEgg() {
try {
Object egg = eggs.take();
System.out.println("消费者取蛋,当前剩余:" + eggs.size());
return egg;
} catch (InterruptedException e) {
e.printStackTrace();
}

return null;
}

/**
* 加入蛋
*
* @return
*/
public void addEgg(Object egg) {
try {
eggs.put(new Object());
System.out.println("生产者生蛋,当前剩余:" + eggs.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
Tester.java
package CreatorAndConsumerBlock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Tester {
public static void main(String[] args)
{
//共享资源
Plate plate = new Plate();
ExecutorService pool = Executors.newFixedThreadPool(100);

//添加生产者和消费者
for(int i = 0 ; i < 100000; i ++)
{
pool.execute(new Creator(plate));
pool.execute(new Consumer(plate));
}

pool.shutdown();
}
}

和使用synchronized关键字和重入锁、条件变量相比,代码大大简化,程序中完全不需要关系线程如何同步资源,什么时候唤醒其他线程。其实,我们查看阻塞队列的源码,其实其也是使用重入锁、条件变量来实现的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: