Fork/Join模型乍看起来很像借鉴了MapReduce,但是具体不敢肯定是什么原因,实际用起来的性能提升是远不如Executor的 。甚至在递归栈到了十层以上的时候,JVM会卡死或者崩溃,从计算机的物理原理来看,Fork/Join框架实际效能也没有想象中的那么美好,所以这篇只稍微谈一下,不再深究 。
Executor框架主要由三个部分组成:任务,任务的执行,异步计算的结果 。
主要的类和接口简介如下:
1. Executor是一个接口,它将任务的提交和任务的执行分离 。
2. ThreadPoolExecutor是线程池的核心,用来执行被提交的类 。
3. Future接口和实现Future接口的FutureTask类,代表异步计算的结果 。
4. Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或其他执行 。
先看一个直接的例子(用SingleThreadExecutor来实现,具体原理下面会阐述):
1 public class ExecutorDemo { 234 public static void main(String[] args){ 56 //ExecutorService fixed= Executors.newFixedThreadPool(4); 7 ExecutorService single=Executors.newSingleThreadExecutor(); 8 //ExecutorService cached=Executors.newCachedThreadPool(); 9 //ExecutorService sched=Executors.newScheduledThreadPool(4);11 12 Callable<String> callable=Executors.callable(new Runnable() {13 @Override14 public void run() {15 for(int i=0;i<100;i++){16 try{17 System.out.println(i);18 }catch(Throwable e){19 e.printStackTrace();20 }21 }22 }23 },"success");24//这里抖了个机灵,用Executors工具类的callable方法将一个匿名Runnable对象装饰为Callable对象作为参数25 Future<String> f=single.submit(callable);26 try {27 System.out.println(f.get());28 single.shutdown();29 }catch(Throwable e){30 e.printStackTrace();31 }32 }33 }如代码中所示,常用一共有四种Exector实现类通过Executors的工厂方法来创建Executor的实例,其具体差别及特点如下所示:
1. FixedThreadPool
这个是我个人最常用的实现类,在Java中最直接的使用方法就是和 Runtime.getRuntime().availableProcessors() 一起使用分配处理器个数个的Executor 。内部结构大致如下:

文章插图
创造实例的函数为: Executors.newFixedThreadPool(int nThread);
在JDK1.7里java.util.concurrent包中的源码中队列使用的是new LinkedBlockingQueue<Runnable>,这是一个无界的队列,也就是说任务有可能无限地积压在这个等待队列之中,实际使用是存在一定的隐患 。但是构造起来相当比较容易,我个人建议在使用的过程之中不断查询size()来保证该阻塞队列不会无限地生长 。
2. SingleThreadExecutor
和 Executors.newFixedThreadPool(1) 完全等价 。
3. CachedThreadPool
和之前两个实现类完全不同的是,这里使用SynchronousQueue替换LinkedBlockingQueue 。简单提一下SynchronousQueue是一个没有容量的队列,一个offer必须对应一个poll,当然所谓poll操作是由实际JVM工作线程来进行的,所以对于使用开发者来讲,这是一个会因为工作线程饱和而阻塞的线程池 。(这个和java.util.concurrent.Exchanger的作用有些相似,但是Exchanger只是对于两个JVM线程的,而SynchronousQueue的阻塞机制是多个生产者和多个消费者而言的 。)
4. ScheduledThreadPoolExecutor
这个实现类内部使用的是DelayQueue 。DelayQueue实际上是一个优先级队列的封装 。时间早的任务会拥有更高的优先级 。它主要用来在给定的延迟之后运行任务,或者定期执行任务 。ScheduledThreadPoolExecutor的功能与Timer类似,但ScheduledThreadPoolExecutor比Timer更加灵活,而且可以有多个后台线程在构造函数之中指定 。
Future接口和ListenableFurture接口
Future接口为异步计算取回结果提供了一个存根(stub),然而这样每次调用Future接口的get方法取回计算结果往往是需要面临阻塞的可能性 。这样在最坏的情况下,异步计算和同步计算的消耗是一致的 。Guava库中因此提供一个非常强大的装饰后的Future接口,使用观察者模式为在异步计算完成之后马上执行addListener指定一个Runnable对象,从实现“完成立即通知” 。
【关于并发框架 Java原生线程池原理及Guava与之的补充】
推荐阅读
- 一文彻底了解Hadoop的来龙去脉
- 人工智能开发 网络爬虫框架Webmagic
- 关于红茶的健康饮用禁忌
- 关于茶的保健常识
- 世界上最早关于哈雷彗星的记录见于 最稀有的天文现象
- 关于用药的小知识,家里有宝宝有老人的要收藏
- 梦见自己和人贩子搏斗砍伤人贩子 梦见自己和人贩子搏斗关于学校录取
- 关于饭后喝铁观音的危害
- Tomcat使用线程池配置高并发连接
- MYSQL关于find_in_set函数的使用详解和like的区别之处
