转载地址:http://yhjhappy234.blog.163.com/blog/static/316328322012324104837102/
6、ThredPoolExecutor
ThredPoolExecutor是基于命令模式下的一个典型的线程池的实现,主要通过一些策略实现一个典型的线程池,目前已知的策略有ThreadPoolExecutor.AbortPolicy, ThreadPoolExecutor.CallerRunsPolicy, ThreadPoolExecutor.DiscardOldestPolicy, ThreadPoolExecutor.DiscardPolicy。废话不多说,我们来看一个示例:
packagecom.yhj.container.concurrent;
importjava.util.concurrent.ArrayBlockingQueue;
importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.CyclicBarrier;
importjava.util.concurrent.Executors;
importjava.util.concurrent.LinkedBlockingDeque;
importjava.util.concurrent.RejectedExecutionException;
importjava.util.concurrent.SynchronousQueue;
importjava.util.concurrent.ThreadPoolExecutor;
importjava.util.concurrent.TimeUnit;
importjava.util.concurrent.atomic.AtomicInteger;
/**
* @Described:线程池测试
* @authorYHJ create at 2012-4-13 下午01:34:03
* @FileNmaecom.yhj.container.concurrent.ThreadPoolExecutorTestCase.java
*/
publicclassThreadPoolExecutorTestCase {
privateAtomicInteger successTask= newAtomicInteger(0);//成功的任务数目
privateAtomicInteger failedTask= newAtomicInteger(0);//失败的任务数目
privateInteger thredCount;//启动的线程数
privateThreadPoolExecutor executor;
privateCountDownLatch latch;//计数器
privateCyclicBarrier cyclicBarrier;//集合点
//构造函数
publicThreadPoolExecutorTestCase(BlockingQueue queue,Integer thredCount) {
super();
System.out.println("queue name:"+queue.getClass());
this.thredCount=thredCount;
executor= newThreadPoolExecutor(10, 500, 30, TimeUnit.SECONDS, queue, Executors.defaultThreadFactory(), newThreadPoolExecutor.AbortPolicy());
}
//要处理的任务列表
classTask implementsRunnable{
privateCountDownLatch latch;//计数器
privateCyclicBarrier cyclicBarrier;//集合点
publicTask(CountDownLatch latch, CyclicBarrier cyclicBarrier) {
super();
this.latch= latch;
this.cyclicBarrier= cyclicBarrier;
}
@Override
publicvoidrun() {
try{
cyclicBarrier.await();//到达预期集合点再执行
} catch(Exception e) {
e.printStackTrace();
}
try{
executor.execute(newRunnable() {
@Override
publicvoidrun() {
try{
Thread.sleep(3000);//休眠3秒
} catch(Exception e) {
e.printStackTrace();
}
latch.countDown();
successTask.incrementAndGet();
}
});
} catch(RejectedExecutionException e) {
latch.countDown();
failedTask.incrementAndGet();
}
}
}
//初始化
publicvoidinit(){
latch= newCountDownLatch(thredCount);
cyclicBarrier= newCyclicBarrier(thredCount);
}
//启动方法
publicvoidstart(){
longstartTime = System.currentTimeMillis();
for(inti=0;i
newThread(newTask(latch, cyclicBarrier)).start();
try{
latch.await();
executor.shutdownNow();
System.out.println("total time:"+(System.currentTimeMillis()-startTime));
System.out.println("success count:"+successTask.intValue());
System.out.println("failed count:"+failedTask.intValue());
System.out.println("===end===");
} catch(Exception e) {
e.printStackTrace();
}
}
//强制关闭方法
publicvoidshutDonw(){
executor.shutdownNow();
}
//主函数
publicstaticvoidmain(String[] args) {
//性能优先 速度优先
ThreadPoolExecutorTestCase testCase = newThreadPoolExecutorTestCase(newSynchronousQueue(), 1000);
testCase.init();
testCase.start();
//稳定优先使用数组缓存队列
testCase=newThreadPoolExecutorTestCase(newArrayBlockingQueue(10), 1000);
testCase.init();
testCase.start();
//稳定优先使用链表缓存队列
testCase=newThreadPoolExecutorTestCase(newLinkedBlockingDeque(10), 1000);
testCase.init();
testCase.start();
//关掉处理器
//testCase.shutDonw();
}
}
运行结果如下:
我们可以看到,通过缓冲可以提升成功率,但是明显消耗的时间大大增加了。
7、Executors
对于线程池,其实也是我们经常用的一个东西,在多线程环境下,线程池是控制并发操作的一个很好的解决方案,但是每次都通过ThredPoolExecutor未免有点麻烦,因此JDK为我们提供可Executors以便我们能轻松的创建ThredPoolExecutor的实例,我们来看以下有哪些快速创建实例的方法:
以上的方法估计也是大家经常用到的,具体的实例我在此也就不多写了。
8、FutureTask
FutureTask可以用户异步获取数据的一种方法,我们前面提到使用ConcurrentHashMap代替HashMap来提升map的性能,但是我们知道,ConcurrentHashMap在进行读操作的时候基本是不加锁的,假设我们有这么一个需求,我们有一个数据库的连接池,默认是不初始化的,在第一次用户用到的时候进行初始化操作。那我们该如何实现的呢?
packagecom.yhj.container.concurrent;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.concurrent.Callable;
importjava.util.concurrent.ConcurrentHashMap;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.CyclicBarrier;
importjava.util.concurrent.FutureTask;
importjava.util.concurrent.locks.ReentrantLock;
/**
* @Described:异步通知测试用例
* @authorYHJ create at 2012-4-14 上午11:31:26
* @FileNmaecom.yhj.container.concurrent.FutureTaskTestCase.java
*/
publicclassFutureTaskTestCase {
//测试需求: 使用一个key-value 形式存储
//测试要求: 所有的连接池对象只能创建一次 且不能加载时初始化 在第一次访问时初始化目标连接池对象
//测试实现: 通过HashMap加锁实现和FutureTask实现
//Map测试任务 用例
interfaceMapTask{
//根据指定的key 获取指定的DB连接key etc:mysql sqlserver oracle DB2 and so on
publicConnection getConnection(String key);
}
//枚举 数据库类型
enumDB_TYPE{
MYSQL(),SQLSERVR,ORACLE,DB2;
}
//使用HashMap加锁实现
classHashMapWithLock implementsMapTask{
privateMap pools= newHashMap();
privateReentrantLock lock= newReentrantLock();
//加锁获取连接对象,防止高并发下数据重复创建
@Override
publicConnection getConnection(String key){
try{
lock.lock(); //锁定操作,后续再来等待
if(!pools.containsKey(key))
pools.put(key, newDBConnectionPool(key));
returnpools.get(key).getConnection();
} finally{
lock.unlock();//解锁操作
}
}
}
//使用ConcurrentHashMap实现,因为ConcurrentHashMap读取时不加锁,因此需要通过回调的方式控制并发
classConcurrentHashMapWithFutureTask implementsMapTask{
privateConcurrentHashMap> pools= newConcurrentHashMap>();
privateFutureTask futureTask;
//通过回调的方式 确保多线程下不会引发多次创建
@Override
publicConnection getConnection(finalString key){
try{
if(!pools.containsKey(key)){
Callable callable = newCallable() {
@Override
publicDBConnectionPool call() throwsException {
pools.put(key,futureTask);
returnnewDBConnectionPool(key);
}
};
FutureTask tmpTask = newFutureTask(callable);
futureTask= pools.putIfAbsent(key, tmpTask);
if(futureTask==null){
futureTask= tmpTask;
futureTask.run();
}
}
returnpools.get(key).get().getConnection();
} catch(Exception e) {
e.printStackTrace();
returnnull;
}
}
}
//DB连接池测试用例供体
classDBConnectionPool{
publicDBConnectionPool(String key) {
System.out.println("创建了"+key+"类型的数据库连接池");
}
//获取DB连接
publicConnection getConnection(){
// create Connection for db
returnnewConnection();
}
}
//DB连接 测试供体
classConnection{
}
//任务执行器 待执行的任务
classExecutorTask implementsRunnable{
privateCyclicBarrier barrier;//计数器
privateCountDownLatch latch;//集合点
privateMapTask task;//待执行的任务
privateString key;
publicExecutorTask(String key,CyclicBarrier barrier, CountDownLatch latch,MapTask task) {
this.barrier= barrier;
this.latch= latch;
this.task= task;
this.key=key;
}
@Override
publicvoidrun() {
try{
barrier.await();//到达集合点之前等待 确保数据是并发执行的
Connection connection = task.getConnection(key);
if(null==connection)
thrownewNullPointerException("Null Connection Exception with "+key);
latch.countDown();
} catch(Exception e) {
e.printStackTrace();
}
}
}
//执行函数
publicvoidexecute(String key,intthredCount,MapTask task){
CyclicBarrier barrier = newCyclicBarrier(thredCount);
CountDownLatch latch = newCountDownLatch(thredCount);
longbeginTime = System.currentTimeMillis();
System.out.println("===start "+task.getClass()+"===");
for(inti=0;i
newThread(newExecutorTask(key, barrier, latch, task)).start();
}
try{
latch.await();
System.out.println("====end "+task.getClass()+" still time "+(System.currentTimeMillis()-beginTime)+"===");
} catch(InterruptedException e1) {
thrownewRuntimeException(e1);
}
}
//启动函数
publicvoidstart(){
intthredCount = 200;
MapTask hashMapWithLock = newHashMapWithLock();
MapTask concurrentHashMapWithFutureTask = newConcurrentHashMapWithFutureTask();
execute("mysql",thredCount, hashMapWithLock);
execute("sqlserver",thredCount, concurrentHashMapWithFutureTask);
}
//主函数
publicstaticvoidmain(String[] args) {
//启动主进程
newFutureTaskTestCase().start();
//等待所有进程结束
while(Thread.activeCount()>1){
Thread.yield();
}
}
}
执行结果如下:
我们看到对象值创建了一次,但是通过回调的方式速度会慢一点,毕竟是异步的,有一部分线程需要等待,但是在多线程的模式下,显然我们可以规避单点访问堆积过大的问题。