- 浏览: 2181180 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
许多情况下,在一个程序中使用多线程是有益处的,可以大大提高程序的效率,多线程主要有以下3个优点1,资源利用率更好2,程序设计在某些情况下更简单3,程序响应更快。当然凡事有利就有弊,多线程也会使程序的开发,维护及调试更加复杂,当然如果我们能够扬长避短,在正确的场合下使用多线程,那么它将成为我们程序中开发的利器。
Java一直以来,对多线程的开发支持比较良好,特别在JDK5,6后引入的java.util.concurrent包,使用多线程的开发变的更加容易,这个包里面大部分的API都是更进一步的封装,作为开发者,我们只需熟悉它怎么使用,就能够很轻松的上手,当然如果你想完全搞懂它,那么就需要读读那些优秀的源码了。
ForkJoinPool这个类是JDK7后新增的线程池,很适合在单机多核的PC上部署多线程程序,ForkJoinPool使用的分而治之的思想,这一点与当前很火的大数据处理框架Hadoop的map/reduce思想非常类似,但是他们的使用场合却不一样,ForkJoinPool适合在一台PC多核CPU上运行,而hadoop则适合在分布式环境中进行大规模集群部署。
Fork/Join 模式有自己的适用范围。如果一个应用能被分解成多个子任务,并且组合多个子任务的结果就能够获得最终的答案,那么这个应用就适合用 Fork/Join 模式来解决.
ForkJoinPool使用的工作窃取的方式能够在最大方式上充分利用CPU的资源,一般流程是fork分解,join结合。本质是将一个任务分解成多个子任务,每个子任务用单独的线程去处理,主要几个常用方法有
关于上表中的ForkJoinTask是一个抽象类,代表一个可以fork与join的任务. ,它还有2个抽象子类:RecursiveAcion和RecursiveTask.其中RecursiveTask代表有泛型返回值的任务.而RecursiveAction代表没有返回值.
下面给出测试代码
有返回值的demo
Java一直以来,对多线程的开发支持比较良好,特别在JDK5,6后引入的java.util.concurrent包,使用多线程的开发变的更加容易,这个包里面大部分的API都是更进一步的封装,作为开发者,我们只需熟悉它怎么使用,就能够很轻松的上手,当然如果你想完全搞懂它,那么就需要读读那些优秀的源码了。
ForkJoinPool这个类是JDK7后新增的线程池,很适合在单机多核的PC上部署多线程程序,ForkJoinPool使用的分而治之的思想,这一点与当前很火的大数据处理框架Hadoop的map/reduce思想非常类似,但是他们的使用场合却不一样,ForkJoinPool适合在一台PC多核CPU上运行,而hadoop则适合在分布式环境中进行大规模集群部署。
Fork/Join 模式有自己的适用范围。如果一个应用能被分解成多个子任务,并且组合多个子任务的结果就能够获得最终的答案,那么这个应用就适合用 Fork/Join 模式来解决.
ForkJoinPool使用的工作窃取的方式能够在最大方式上充分利用CPU的资源,一般流程是fork分解,join结合。本质是将一个任务分解成多个子任务,每个子任务用单独的线程去处理,主要几个常用方法有
fork( ForkJoinTask) | 异步执行一个线程 |
join( ForkJoinTask) | 等待任务完成并返回执行结果 |
execute( ForkJoinTask) | 执行不带返回值的任务 |
submit( ForkJoinTask) | 执行带返回值的任务 |
invoke( ForkJoinTask) | 执行指定的任务,等待完成,返回结果。 |
invokeAll(ForkJoinTask) | 执行指定的任务,等待完成,返回结果。 |
shutdown() | 执行此方法之后,ForkJoinPool 不再接受新的任务,但是已经提交的任务可以继续执行。如果希望立刻停止所有的任务,可以尝试 shutdownNow() 方法。 |
awaitTermination(int, TimeUnit.SECONDS) | 阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束。 |
compute() | 执行任务的具体方法 |
Runtime.getRuntime().availableProcessors() | 获取CPU个数的方法 |
关于上表中的ForkJoinTask是一个抽象类,代表一个可以fork与join的任务. ,它还有2个抽象子类:RecursiveAcion和RecursiveTask.其中RecursiveTask代表有泛型返回值的任务.而RecursiveAction代表没有返回值.
下面给出测试代码
package com.demo; import java.util.concurrent.RecursiveAction; /** * * 继承RecursiveAction来实现可分解的任务 * 注意无返回值 * * **/ public class PrintTask extends RecursiveAction { //每个小任务,最多只打印50个数 private static final int threshold=50; //打印任务的开始 private int start; //打印任务的结束 private int end; public PrintTask() { // TODO Auto-generated constructor stub } //打印从start到end之间的任务 public PrintTask(int start, int end) { super(); this.start = start; this.end = end; } @Override protected void compute() { if(end-start<threshold){ for(int i=start;i<end;i++){ System.out.println(Thread.currentThread().getName()+"i的值:"+i); } }else{ //当end与start之间的差大于threshold,及打印的数超过50个时, //将大任务分解成2个小任务 int middle=(start+end)/2; PrintTask left=new PrintTask(start, middle); PrintTask right=new PrintTask(middle, end); //并行执行两个小任务 left.fork(); right.fork(); } } }
package com.demo; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.TimeUnit; /** * 测试打印 * * */ public class Test { public static void main(String[] args)throws Exception { ForkJoinPool pool=new ForkJoinPool(); //提交可分解的任务 pool.submit(new PrintTask(0,101)); //阻塞等待所有任务完成 pool.awaitTermination(2, TimeUnit.SECONDS); pool.shutdown();//关闭线程池 } }
有返回值的demo
package com.demo; import java.util.concurrent.RecursiveTask; /*** * 有返回值 * * */ public class CalTask extends RecursiveTask<Integer>{ //将每个小任务,最多只能累加20个数 private static final int threshold=20; private int arr[]; private int start;//开始 private int end;// //累加从start到end之间的数 public CalTask() { // TODO Auto-generated constructor stub } //累加从start到end的数组元素 public CalTask(int[] arr, int start, int end) { super(); this.arr = arr; this.start = start; this.end = end; } @Override protected Integer compute() { int sum=0; //当end与start之间的差小于threshold,开始进行累加 if(end-start<threshold){ for(int i=start;i<end;i++){ sum+=arr[i]; } return sum; }else{ //当end与start之间的差大于threshold,要计算的数超过20个时, //将大任务分解成两个小任务 int middle=(start+end)/2; CalTask left=new CalTask(arr, start, middle); CalTask right=new CalTask(arr, middle, end); //并行执行2个小任务 left.fork(); right.fork(); //把2个小任务,累加的结果合并起来 return left.join()+right.join(); } } }
package com.demo; import java.util.Random; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; public class Sum { public static void main(String[] args)throws Exception { int []arr=new int[1100]; Random rand=new Random(); int total=0; //初始化100个数字 for(int i=0;i<arr.length;i++){ int tmp=rand.nextInt(20); //对元素赋值,并将数组元素的值添加到total总和中 total+=(arr[i]=tmp); } System.out.println("正确的total:"+total); ForkJoinPool pool=new ForkJoinPool(); //提交可分解的CalTask任务 Future<Integer> future=pool.submit(new CalTask(arr, 0, arr.length)); System.out.println(future.get()); //关闭线程池 pool.shutdown(); } }
评论
1 楼
ksisn
2014-11-22
楼主您好,很荣幸能拜读到您的博客,我是刚毕业的程序猿,用您这篇文章的例子进行一些测试,发现比单线程方式在时间上慢了很多倍,那么像这种ForkJoinPool 适用的场景又是什么呢,一直在拜读您的例子中,这个没弄懂,特地请教您。
发表评论
-
记一次log4j不打印日志的踩坑记
2019-09-22 01:58 1557### 起因 前几天一个跑有java应用的生产集群(200多 ... -
在Java里面如何解决进退两难的jar包冲突问题?
2019-07-23 19:10 1228如上图所示: es api组件依赖guava18.0 ... -
如何轻松理解二叉树的深度遍历策略
2019-07-03 23:33 1119我们知道普通的线性数据结构如链表,数组等,遍历方式单一 ... -
为什么单线程Redis性能也很出色
2019-01-21 18:02 2202高性能的服务器,不一 ... -
如何将编程语言里面的字符串转成数字?
2019-01-11 23:23 2087将字符串转成数字在很 ... -
为什么Java里面String类是不可变的
2019-01-06 18:36 1664在Java里面String类型是不可变对象,这一点毫无疑问,那 ... -
关于Java里面volatile关键字的重排序
2019-01-04 18:49 1062Java里面volatile关键字主 ... -
多个线程如何轮流打印ABC特定的次数?
2018-12-11 20:42 6032之前的一篇文章,我给 ... -
聊聊Java里面的引用传递
2018-11-16 21:21 988长久以来,在Java语言里面一直有一个争论,就是Java语言到 ... -
理解计数排序算法的原理和实现
2018-10-11 10:03 2088计数排序(Counting sort) ... -
理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略
2018-09-06 11:31 3385### 前言 理解HashMap和Con ... -
关于Java里面多线程同步的一些知识
2018-07-18 09:45 1103# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
Java单例模式之双检锁深入思考
2018-07-08 12:25 3287# Java单例模式之双检锁 ... -
关于Java里面多线程同步的一些知识
2018-07-08 12:23 1119# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
重新认识同步与异步,阻塞和非阻塞的概念
2018-07-06 14:30 1469# 重新认识同步与异步 ... -
线程的基本知识总结
2018-06-27 16:27 1057### (一)创建线程的方式 (1)实现Runnable接口 ... -
Java里面volatile关键字修饰引用变量的陷阱
2018-06-25 11:42 1384# Java里面volatile关键字修饰引用变量的陷阱 如 ... -
关于Java里面的字符串拼接,你了解多少?
2018-06-25 11:28 1365# 关于Java里面的字符串 ... -
深入理解Java内存模型的语义
2018-06-25 11:39 735### 前言 Java内存模型( ... -
如何证明Java多线程中的成员变量数据是互不可见的
2018-06-21 10:09 1497前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义, ...
相关推荐
线程池ForkJoinPool是Java并发编程中的一个重要工具,它是Java 7引入的一个新特性,主要用于优化并行计算,特别是在处理大量可分任务时,如递归算法。ForkJoinPool是基于工作窃取(Work-Stealing)算法的线程池,...
Java线程池ForkJoinPool实例解析是Java并发编程中的一种高级主题,ForkJoinPool是Java 7中引入的一种新的线程池实现,它可以充分利用多CPU和多核CPU的优势,使得并发编程变得更加高效。 ForkJoinPool的优势在于,...
- **定义**: `ForkJoinPool`是Java 7引入的一种用于执行大量细粒度并行任务的线程池。 - **特点**: 它主要通过`Fork-Join`框架实现,能够有效地管理并行任务,特别是适用于那些可以被细分为更小任务的任务类型。 ##...
Java中的ForkJoinPool是Java 7引入的一种新的线程池实现,它是为了解决大量并行计算场景下的效率问题而设计的。ForkJoinPool的设计理念基于分治策略(Divide and Conquer),适用于那些可以拆分成多个子任务的任务,...
知识点:可以使用ForkJoinPool的构造方法并设定并行级别来创建一个自定义的线程池。 4. 总结 我们简要地看了一下,如何使用一个自定义的Thread Pool运行并行流。只要在正确的环境中配置了合适的平行级别,就能在...
Java多线程编程中的ForkJoinPool实例详解是Java 7中引入的一种高效的并发编程框架。ForkJoinPool是ExecutorService接口的实现,它管理工作窃取算法(Work-Stealing Algorithm)实现高效的任务执行和线程管理。 ...
所有并行流执行都使用相同的(单例)线程池:ForkJoinPool.commonPool()。 这就是为什么在并行流中执行 IO(更常见的是阻塞调用)非常糟糕的原因:被阻塞的线程无法被 JVM 中的所有并行流使用。 为此,您必须改用 ...
13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、有序性、原子性与JMM内存模型 (1).pdf 15、CPU缓存架构详解&高性能内存队列Disruptor 实战 (1).pdf 16、常用并发设计模式精讲 (1)....
13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、有序性、原子性与JMM内存模型 (1).pdf 15、CPU缓存架构详解&高性能内存队列Disruptor 实战 (1).pdf 16、常用并发设计模式精讲 (1)....
13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、有序性、原子性与JMM内存模型 (1).pdf 15、CPU缓存架构详解&高性能内存队列Disruptor 实战 (1).pdf 16、常用并发设计模式精讲 (1)....
13、线程池 ForkJoinPool实战及其工作原理分析 (1).pdf 14、深入理解井发可见性、有序性、原子性与JMM内存模型 (1).pdf 15、CPU缓存架构详解&高性能内存队列Disruptor 实战 (1).pdf 16、常用并发设计模式精讲 (1)....
`ForkJoinPool`是Java 7引入的,用于支持`Fork/Join`框架,适合进行大量计算任务,如并行排序。它有自己的工作窃取算法,线程会主动去寻找其他已完成或未开始的任务来执行,提高并行性。 线程池的选择应根据实际...
5. ForkJoinPool:用于执行Fork/Join框架的任务,适用于分割任务并行执行的场景。 ThreadPoolExecutor是线程池的核心实现,其构造函数的参数定义了线程池的行为: - corePoolSize:核心线程数,即使无任务,这些...
Java 7 引入了一种新的并发编程框架——ForkJoinPool,它是基于分而治之(Divide and Conquer)策略的并行计算模型。ForkJoinPool 和与其配合使用的 RecursiveAction 和 RecursiveTask 类,为开发者提供了更高效地...
- 对于短生命周期的任务,可选择`ForkJoinPool`或`ThreadPoolExecutor`配合`WorkStealingPool`。 - 定期分析线程池状态,根据实际情况调整参数。 理解并熟练运用Java线程池,不仅可以提升程序性能,还能有效控制...
客户端代码中,首先创建一个ForkJoinPool实例,通常我们会使用ForkJoinPool.commonPool()来获取一个默认的线程池。然后,提交一个Task实例,ForkJoinPool会自动处理任务的拆分和结果的合并。最后,通过调用Task的get...
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; public class SumCalculator extends RecursiveAction { private int[] array; private int start; private int end;...
例如,`Executors`类提供了几个预设的线程池构造方法,如`newFixedThreadPool`(固定大小线程池)、`newSingleThreadExecutor`(单线程线程池)和`newWorkStealingPool`(ForkJoinPool,适用于并行计算)。...
在Java 7中,`ForkJoinPool`和`RecursiveTask`或`RecursiveAction`是新增的重要特性,用于执行可拆分的计算任务,尤其适合大数据处理。`ForkJoinPool`使用工作窃取算法,使得线程能有效地平衡负载,提高并行性。 接...