生产者消费者问题作为多线程中helloworld,是每个多线程开发人员入门必须掌握的。生产者消费者问题在开发当中应用广泛,如最常接触的线程池实现,多种阻塞消息队列中。下面介绍一下用java.util.concurrent.BlockingQueue实现和自己编写一个Storage实现简单部分类似BlockingQueue的功能。
public class ProducerAndConsumerImplByBlockingQueue {
public static void main(String[] args) {
//Storage store = new Storage();
BlockingQueue<String> queue = new LinkedBlockingQueue<String>(20);//定义 BlockingQueue的大小为20
Thread t1 = new Thread(new Producer1(queue));
Thread t2 = new Thread(new Consumer1(queue));
t1.start();
t2.start();
}
}
/**
* 生产者线程
* @author YZJ
*
*/
class Producer1 implements Runnable {
private BlockingQueue<String> queue;
public Producer1(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
int i = 1;
while(true){
try {
System.out.println("生产产品:"+i);
queue.put("产品"+i++);
Thread.sleep(200);//线程睡眠时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者线程
* @author YZJ
*
*/
class Consumer1 implements Runnable {
private BlockingQueue<String> queue;
public Consumer1(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
System.out.println("消费产品:"+queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
LinkedBlockingQueue用链表的方式实现FIFO,采用ReentrantLock进行同步,关于ReentrantLock机制大家可自行查阅相关文章,作者在后续中也会对ReentrantLock原理进行简单分析。除LinkedBlockingQueue以外,BlockingQueue的常用实现还有ArrayBlockingArray,内部采用数组实现,类似于LinkedList和ArrayList的关系。其他实现还有PriorityBlocingQueue,SynchronousQueue。PriorityBlocingQueue于采用自然排序或自定义comparator实现排序而非FIFO;SynchronousQueue则是实现一放一取的队列。
2.自定义Storage
public class ProducerAndConsumer {
public static void main(String[] args) {
Storage store = new Storage();
Thread t1 = new Thread(new Producer(store));
Thread t2 = new Thread(new Consumer(store));
t1.start();
t2.start();
}
}
/**
* 生产者线程
* @author YZJ
*
*/
class Producer implements Runnable {
private Storage storage;
public Producer(Storage storage){
this.storage = storage;
}
@Override
public void run() {
int i = 1;
while(true){
storage.push("产品"+i++);
}
}
}
/**
* 消费者线程
* @author YZJ
*
*/
class Consumer implements Runnable {
private Storage storage;
public Consumer(Storage storage){
this.storage = storage;
}
@Override
public void run() {
while(true){
storage.pop();
}
}
}
/**
* 阻塞队列,存放产品
* @author YZJ
*
*/
class Storage{
private List<String> list = new ArrayList<String>();
public void push(String product){
synchronized(this){
list.add(product);
System.out.println("生产产品:"+product);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if(list.size()==20){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
}
}
public void pop(){
synchronized(this){
if(list.size()>0){
System.out.println("消费产品:"+list.get(0));
list.remove(0);
}else{
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
}
}
public List<String> getList(){
return list;
}
}
Storage同样采用FIFO策略,简单实现阻塞队列,若需要更改策略,可修改pop中提取策略即可。