七、线程并发高级部分之JDK7新增的Fork/Join

化繁为简,分而治之。利用递归的分解和合并,直到任务小到可以接受的程度。

1. Future任务机制和FutureTask

Future类对具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。

boolean cancel(boolean mayInterruptIfRunning):取消任务,参数表示是否允许取消正在执行却没有执行完毕的任务。
boolean isCancelled() :任务是否取消成功,如果在完成之前取消则为true。
boolean isDone():任务是否已经完成。
Object get(): 获取执行结果,会产生阻塞,等到任务执行完毕才返回。
Object get(long timeout, TimeUnit unit): 在指定时间内获取执行结果,超出时间返回为null。

Future功能:判断任务是否完成;能够中断任务;获取任务执行结果。

Future只是接口无法用来创建对象使用,因此有了FutureTask。
构造器内容:
public FutureTask(Runnable runnable, V result):返回给定的结果
public FutureTask(Callable callable) :执行给定的Callable。

2. Fork/Join框架

概念:java7提供的用于并行执行任务的框架 ,将大任务分割成若干小任务,最终汇总到每个小任务结果后得到大任务结果的框架。

代码实例:执行1+2+3+4的结果

public class ForkJoinTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        CountTask countTask = new CountTask(1, 5);
        ForkJoinTask<Integer> result = forkJoinPool.submit(countTask);
        System.out.println("result = " + result.get());

    }
    static class CountTask extends RecursiveTask<Integer> {
        private static int splitSize = 2;
        private int start, end;

        public CountTask(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Integer compute() {
            int sum = 0;
            //如果任务不需要再拆分就开始计算
            boolean canCompute = (end - start) <= splitSize;
            if (canCompute) {
                for (int i = start; i <= end; i++) {
                    sum = sum + i;
                }
            } else {
                //拆分成两个子任务
                int muddle = (start + end) / 2;
                CountTask firstTask = new CountTask(start, muddle);
                CountTask secondTask = new CountTask(muddle + 1, end);
                //开始执行
                firstTask.fork();
                secondTask.fork();
                //获得子任务结果,得不到记过线程不会继续往下执行
                Integer firstResult = firstTask.join();
                Integer secondResult = secondTask.join();
                //合并两个子task执行结果
                sum = firstResult + secondResult;
            }
            return sum;
        }
    }
}

3. ForkJoin的JDK家族

3.1 ForkJoinTask
实现Future 的另一种有结果的实现方法,比Future多了两个重要的方法,
fork():创建新任务;join()计算完成后返回结果。

RecursiveAction:继承ForkJoinTask,用于没有返回结果的任务。
RecursiveTask:继承ForkJoinTask,用于有返回结果的任务。

ForkJoinPool:实现Executor接口。
ForkJoinPool提供三个方法来调度子任务:
execute:异步执行指定任务;
invoke:执行指定的任务,等待完成,返回结果;
submit:异步执行指定任务,立即返回一个Future对象。

4. Fork/Join框架实现原理

利用工作窃取算法,使空闲线程主动分担从其他线程分解出来的子任务。使用双端队列,窃取线程从尾部,被窃取线程从头部执行任务。
缺点:当有一个任务时,消耗更多系统资源创建多个线程和多个双端队列。

5. 异常处理机制

通过isCompletedAbnormaly()方法来检查任务是否抛出异常,通过ForkJoinTask的getException方法获异常。方法返回Throwable对象,如果任务取消,返回CancellationException。没有任务完成或者没有抛出异常则返回null。

6. Fork/Join模式优缺点及实际应用场景

优点:更方便利用多核平台计算能力,解决死锁问题。仅仅关注如何划分任务和组合中间结果就可以。对于树形结构类型的数据处理和便利非常适合。

7. 合理设计和配置线程池

最大限度发挥单台物理server机器的最大并发量(线程数),但不至于系统崩溃。需要知道本台server最大可响应的并发量是多少,极限并发量是多少,可以利用压测。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值