thread_fork/join并发框架2
转自 http://blog.csdn.net/mr_zhuqiang/article/details/48300229
三.使用异步方式
invokeAll(task1,task2); 是同步方式,将当前任务挂起直到子任务发送到 Fork/join线程池中执行完成,这种方式允许工作窃取算法,分配一个新任务给在执行休眠任务的工作者线程。
相反当采用异步的方式(比如,fork()),任务将继续执行,所以就没有办法使用工作窃取算法了。因为不存在等待的线程了。除非使用join() 或则 get() 来获取结果,等待任务的完成。
invokeAll()采用同步方式,工作者线程将会休眠等待子任务的完成,所以能使用窃取算法派给工作者一个新任务
fork() 采用异步方式,只有结合join()或者get() 来等待任务的完成,进而可以使用窃取算法来提高性能。
get():如果ForkJoinTask类执行结束,或则一直等到结束,那么get()方法的这个版本则返回由compute()方法返回的结果
get() 方法 和 join()方法的区别:
join()方法不能被中断,如果中断join()方法的线程,方法将抛出Interrupted异常
如果任务抛出任何运行时异常,那么get()方法将返回ExecutionException异常,但是join方法返回的是RuntimeException;
- public class ForkJoin3Test {
- public static void main(String[] args) throws InterruptedException {
- ForkJoinPool pool = new ForkJoinPool();
- Task3 mp3 = new Task3("C:\\360CloudUI", "mp3");
- pool.execute(mp3);
- do {
- System.out.println("*********** 状态信息巡查 ***************");
- System.out.printf("最大并行任务:%s,当前活动任务数(不准确的):%s,队列中的任务数量:%s,窃取数量:%s\n",
- pool.getParallelism(),
- pool.getActiveThreadCount(),
- pool.getQueuedTaskCount(),
- pool.getStealCount());
- TimeUnit.MILLISECONDS.sleep(10);
- } while (!mp3.isDone()); // 未完成则一直循环获取状态信息
- pool.shutdown();
- List<String> join = mp3.join();
- System.out.println("共找到符合的文件数量:" + join.size());
- for (String s : join) {
- System.out.println(s);
- }
- }
- }
- class Task3 extends RecursiveTask<List<String>> {
- private static final long serialVersionUID = 1L;
- private String path; // 文件夹路径
- private String suffix; // 后缀
- public Task3(String path, String suffix) {
- this.path = path;
- this.suffix = suffix;
- }
- @Override
- protected List<String> compute() {
- List<String> result = new ArrayList<String>(); // 存储结果
- List<Task3> tasks = new ArrayList<Task3>(); // 存储任务
- File file = new File(path);
- File[] files = file.listFiles();
- for (File f : files) { // 分发和执行任务
- if (f.isDirectory()) { // 如果是文件夹,则使用异步的方式发送一个任务去执行
- Task3 task = new Task3(f.getAbsolutePath(), suffix);
- task.fork(); // 拆分任务异步执行
- tasks.add(task);
- } else {
- String name = f.getName();
- if (name.endsWith(suffix)) {
- result.add(name);
- }
- }
- }
- if (tasks.size() > 1) { // 如果当前任务大于1个 则打印信息
- System.out.printf("%s,tasks size(当前路径有) = %s个(文件夹),当前路径是:%s\n", Thread.currentThread().getName(),
- tasks.size(), path);
- }
- for (Task3 task : tasks) { // 获取当前任务的结果
- List<String> join = task.join(); // 调用join方法等待任务完成
- result.addAll(join); // 把任务结果添加到当前任务的结果中
- }
- return result;
- }
- }
四 取消任务
ForkJoinTask 对象中有一个cancel()方法来取消未开始的任务。取消任务有以下两点需要注意:
1. ForkJoinPool类不提供任何方法来取消线程池中正在运行或则等待运行的所有任务。
2. 取消任务时,不能取消已经被执行的任务。
- public class ForkJoin4Test {
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- int[] arrs = new ArrayGenerator().generateArray(50);
//- TaskManger taskManger = new TaskManger();
- ForkJoinPool pool = new ForkJoinPool();
- SearchNumberTask task = new SearchNumberTask(arrs, 0, arrs.length, 50, taskManger);
- pool.execute(task);
- pool.shutdown();
- pool.awaitTermination(1, TimeUnit.MILLISECONDS);
- // System.out.println("main:结束:" + task.get());
- }
- }
- // 数组生成
- class ArrayGenerator {
- public int[] generateArray(int size) {
- int[] array = new int[size];
- Random random = new Random();
- for (int i = 0; i < size; i++) {
- array[i] = random.nextInt(10);
- }
- return array;
- }
- }
- // 任务管理类
- class TaskManger {
- private List<ForkJoinTask<Integer>> tasks = new ArrayList<ForkJoinTask<Integer>>();
- public void addTask(ForkJoinTask<Integer> task) {
- tasks.add(task);
- }
- public void cancelTasks(ForkJoinTask<Integer> cancelTask) {
- for (ForkJoinTask<Integer> task : tasks) {
- if (task != cancelTask) {
- task.cancel(true);
- ((SearchNumberTask) task).writeCanceMesg();
- }
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- class SearchNumberTask extends RecursiveTask<Integer> {
- private int[] numbers;
- private int start, end;
- private int number;
- private TaskManger taskManger;
- private final static int NOT_FOUND = -1;
- public SearchNumberTask(int[] numbers, int start, int end, int number, TaskManger taskManger) {
- this.numbers = numbers;
- this.start = start;
- this.end = end;
- this.number = number;
- this.taskManger = taskManger;
- }
- @Override
- protected Integer compute() {
- int ret;
- if (end - start > 10) { // 拆分任务
- ret = launchTasks();
- } else { // 执行查找
- System.out.println("Task:开始:" + start + ":" + end);
- ret = lookForNumber();
- System.out.println("Task:结束--------:" + start + ":" + end);
- }
- return ret;
- }
- /**
- * 查找数字
- *
- * @return
- */
- private int lookForNumber() {
- for (int i = start; i < end; i++) {
- if (numbers[i] == number) {
- System.out.printf("Task:目标number:%s已被找到,索引位置:%s\n", number, i);
- taskManger.cancelTasks(this);
- return i;
- }
- }
- return NOT_FOUND;
- }
- /**
- * 拆分任务
- *
- * @return
- */
- private int launchTasks() {
- int mid = (start + end) / 2;
- SearchNumberTask task1 = new SearchNumberTask(numbers, start, mid, number, taskManger);
- SearchNumberTask task2 = new SearchNumberTask(numbers, mid, end, number, taskManger);
- taskManger.addTask(task1);
- taskManger.addTask(task2);
- task1.fork(); // 异步执行
- task2.fork();
- int result = task1.join();
- if (result != -1) {
- return result;
- }
- return task2.join();
- }
- /** 取消任务 信息 **/
- public void writeCanceMesg() {
- System.out.printf("Task:取消了,start=%s,end=%s\n", start, end);
- }
- }
五 运行异常
Java有两种类型的异常:
非运行时异常(Checked Exception):必须在方法上通过throws 子句抛出,或则通过try…catch语句进行扑捉处理。
运行时异常(Unchecked Exception):不是强制的需要捕捉处理和throws抛出。
在ForkJoinTask类的compute方法中不能抛出非运行时异常,因为该方法没有throws的声明,根据Java重新方法的规则,所以不能抛出。而且在该compute中抛出的运行时异常,给我最明显直观的结果是,只要不调用get()获取结果,控制台是不会打印异常信息的。也就是说,异常被吞噬了。但是我们可以通过该类的其他方法来获取该异常。
task.isCompletedNormally() : 任务完成时没有出错
task.isCompletedAbnormally() : 来检查任务是否已经抛出异常或已经被取消了,要注意此方法。由于提交任务之后,检测该任务是否有异常,不是阻塞的。所以需要等待任务的完成。才能正确的获取到是否有异常
task.getException() : 获得任务中抛出的异常
该类中抛出的异常,只要一抛出异常,子任务都不会再继续执行。(反正就是说只要抛出了异常,任务结果肯定是不正确的了)
completeExceptionally(Throwable ex) : 该方法 可以在语义上抛出一个异常,包括非运行时异常。要在获取结果前 通过task.isCompletedAbnormally()来配合操作。
- public class ForkJoin5Test {
- public static void main(String[] args) throws InterruptedException {
- int[] arrs = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- ForkJoinPool pool = new ForkJoinPool(1);
- Task5 task = new Task5(arrs, 0, arrs.length);
- pool.execute(task);
- pool.shutdown(); // 关闭执行器,并配合超时。来等待任务运行完成,发现一个特性:该执行器如来里面没有可活动的任务。执行器会自动关闭。而且调用get会阻塞任务直到返回结果
- pool.awaitTermination(1, TimeUnit.DAYS);
- // task.isCompletedNormally() 任务完成时没有出错
- if (task.isCompletedAbnormally()) { // 来检查任务是否已经抛出异常或已经被取消了,要注意此方法。由于提交任务之后,检测该任务是否有异常,不是阻塞的。所以需要上面的等待任务的完成。才能正确的获取到是否有异常
- System.out.println("检测到任务中有抛出的异常:" + task.getException().getMessage());
- } else {
- System.out.println(task.join());
- }
- }
- }
- class Task5 extends RecursiveTask<Integer> {
- private int[] arrs; // 要处理的数据
- private int start; // 开始索引
- private int end; // 结束索引
- public Task5(int[] arrs, int start, int end) {
- this.arrs = arrs;
- this.start = start;
- this.end = end;
- }
- @Override
- protected Integer compute() {
- int result = 0;
- if (end - start < 2) {
- for (int i = start; i < end; i++) {
- result += arrs[i];
- }
- System.out.printf("%s,结果:%s\n", Thread.currentThread().getName(), result);
- return result;
- } else {
- int mid = (start + end) / 2;
- // System.out.println(mid);
- if (mid == 2) {
- throw new RuntimeException("故意抛出的测试异常"); // 为了测试抛出异常,可以
- // 关闭测异常。运行查看结果
- // Exception e = new Exception("故意抛出的非运行时异常");
- // completeExceptionally(e); //也可以使用 该方法,设置一个异常,因为 源码
- // setExceptionalCompletion
- // 是设置的异常,就相当于该异常并没有被抛出。在语义上通过task.isCompletedAbnormally()来抛出了非运行时异常
- // return null; // 如果不返回,程序将继续执行后面的代码,并不能达到真正抛出异常的效果
- }
- // 拆分成2个子任务继续检测和执行
- Task5 task1 = new Task5(arrs, start, mid);
- Task5 task2 = new Task5(arrs, mid, end);
- invokeAll(task1, task2); // 使用同步的方式 执行
- try {
- result = task1.get() + task2.get(); // 把子任务返回的结果相加
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- }
thread_fork/join并发框架2的更多相关文章
- thread_fork/join并发框架1
一.线程并发控制 Thread.Executor.ForkJoin和Actor 1.裸线程 Runnable接口,调用.start()开始,没有现成的API来结束线程,你需要自己来实现, ...
- Java 7 Fork/Join 并行计算框架概览
应用程序并行计算遇到的问题 当硬件处理能力不能按摩尔定律垂直发展的时候,选择了水平发展.多核处理器已广泛应用,未来处理器的核心数将进一步发布,甚至达到上百上千的数量.而现在 很多的应用程序在运行在多核 ...
- Java 并发系列之十:java 并发框架(2个)
1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...
- 深入理解Java并发框架AQS系列(一):线程
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...
- 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock)
一.前言 优秀的源码就在那里 经过了前面两章的铺垫,终于要切入正题了,本章也是整个AQS的核心之一 从本章开始,我们要精读AQS源码,在欣赏它的同时也要学会质疑它.当然本文不会带着大家逐行过源码(会有 ...
- 协程并发框架gevent及其用法
gevent是python的一个并发框架,采用协程实现并发目的,用起来也非常简单 gevent的docs:http://www.gevent.org/contents.html 一个最简单的例子: i ...
- Python 开源异步并发框架的未来
http://segmentfault.com/a/1190000000471602 开源 Python 是开源的,介绍的这几个框架 Twisted.Tornado.Gevent 和 tulip 也都 ...
- Python开源异步并发框架
Python开源异步并发框架的未来 2014年3月30日,由全球最大的中文IT社区CSDN主办的“开源技术大会·” (Open Source Technology Conference ,简称OSTC ...
- J.U.C并发框架
转载:http://itindex.net/detail/48869-j.u.c-%E6%A1%86%E6%9E%B6 J.U.C并发框架 作者:Doug Lea SUNY Oswego Oswego ...
随机推荐
- mediawiki的安装与配置
apache的配置: 1. 开启php module 查看mods-enabled/php5.load 是否存在,不存在的话, 就从mods-avaliable中复制一个到mods-enabled中. ...
- asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler” http:// ...
- wordpress自动保存远程图片插件 DX-auto-save-images
wordpress自动保存远程图片插件DX-auto-save-images 解决了保存文章就可以自动将远程图片保存到你的服务器上了. 具体操作步骤如下: 1.安装启用wordpress自动保存远程图 ...
- java web项目启动时自动加载自定义properties文件
首先创建一个类 public class ContextInitListener implements ServletContextListener 使得该类成为一个监听器.用于监听整个容器生命周期的 ...
- 8 个最优秀的 Android Studio 插件
Android Studio是目前Google官方设计的用于原生Android应用程序开发的IDE.基于JetBrains的IntelliJ IDEA,这是Google I/O 2013第一个宣布的作 ...
- SQLServer查询执行计划分析 - 案例
SQLServer查询执行计划分析 - 案例 http://pan.baidu.com/s/1pJ0gLjP 包括学习笔记.书.样例库
- elasticsearch + hive环境搭建
一.环境介绍: elasticsearch:2.3.1 hive:0.12 二.环境搭建 2.1 首先获取elasticsearc-hadoop的jar包 链接地址:http://jcenter.bi ...
- “享受”英语的快乐—我是如何学英语的
一:扬长避短重新认识英语课本 目前市场上的课本都有弊端,<新概念><走遍美国><疯狂英语>等等,不怪你学不下去,不是你的问题,课本本身就有漏洞的,但我怎么学的呢,我 ...
- web通过ActiveX打印
最近做了一个activex控件,可以通过html页面动态设置报表文件的数据,控件里的报表是通过FastReport实现了,可以通过FastReport先把报表设置好.欢迎大家提意见 控件及Demo下载
- 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...