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
和使用synchronized关键字和重入锁、条件变量相比,代码大大简化,程序中完全不需要关系线程如何同步资源,什么时候唤醒其他线程。其实,我们查看阻塞队列的源码,其实其也是使用重入锁、条件变量来实现的。
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关键字和重入锁、条件变量相比,代码大大简化,程序中完全不需要关系线程如何同步资源,什么时候唤醒其他线程。其实,我们查看阻塞队列的源码,其实其也是使用重入锁、条件变量来实现的。
相关文章推荐
- Java中的方法和数组
- axis2开发之---生成Java代码(4)
- spring web项目 数据库用户名密码加密解密
- Java中的程序结构
- MyEclipse生成javadoc时出错:编码GBK的不可映射字符"解决办法
- eclipse 无法加载 android sdk 列表
- Eclipse之NDK编译——常见异常的解决办法记录
- 调试JDK源码-HashSet实现原理
- 深入理解Java内存模型系列
- 学习Spring必学的Java基础知识(2)----动态代理
- Java基础笔记
- java学习笔记4
- JAVA_SE基础——57.有了包之后类与类之间的访问
- java模拟登录。不会存在跨域问题
- Android Studio快捷键设置成跟Eclipse一样
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- jvm 常用配置
- 五子棋AI图形界面人机对战(JAVA实现)
- Programming in Java: Multi-threads and interface vs abstract class