【Java】多线程框架

Fork / Join 框架

Fork/Join框架是Java7提供的用于并行执行任务的框架
是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架

框架设计
  1. 分割任务
  2. 执行任务,合并结果
代码实例
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

public class CountTask extends RecursiveTask<Integer>{
    private static final int THRESHOLD = 2;
    private int start;
    private int end;

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

    @Override
    protected Integer compute(){
        int sum = 0;
        //任务足够小就计算任务
        boolean canCompute = (end-start) <= THRESHOLD;
        if(canCompute){
            for(int i = start; i<=end; i++){
                sum += i;
            }
        }else{
            //如果任务大于阈值,就分裂成两个子任务计算
            int middle = (start + end) / 2;
            CountTask leftTask = new CountTask(start,middle);
            CountTask rightTask = new CountTask(middle+1,end);
            //执行子任务
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();
            //合并子任务
            sum = leftResult + rightResult;
        }
        return sum;
    }
}

public static void main(String[] args){
    ForkJoinPool forkJoinPool = new ForkJoinPool();
    CountTask task = new CountTask(1,4);
    Future<Integer> result = forkJoinPool.submit(task);
    try{
        System.out.pirntln(result.get());
    }catch(InterruptedException e){ 
    }catch(ExecutionException e){
    }
}

Executor 框架

Java中的线程即是工作单元也是执行机制,从JDK 5后,工作单元与执行机制被分离。工作单元包括Runnable和Callable,执行机制由JDK 5中增加的java.util.concurrent包中Executor框架提供。

HotSpot VM的线程模型中将java的线程映射为本地操作系统的线程,java线程的启动意味着一个本地操作系统线程的创建,而java线程的终止也就意味着对应的系统线程的回收。

框架结构

这里写图片描述

应用程序通过Executor框架控制上层的调度;下层的调度由操作系统内核控制

  • 任务:包括执行任务需要的接口(Runnable接口或Callable接口)
  • 任务的执行:包括Executor接口和ExecutorService接口(有两个类实现该接口ThreadPoolExecutor和ScheduledThreadPoolExecutor)
  • 异步计算的结果:包括Future接口和实现Future接口的FutureTask类
代码实例
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorTest {
    public static void main(String[] args) {
        Random random = new Random();
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            numbers.add(random.nextInt(100000));
        }
        int result = calculate(numbers, 3);
        System.out.println(result);
    }

    public static int calculate(List<Integer> numbers,int digit) {
        List<Callable<Integer>> tasks = new ArrayList<>();
        for (Integer x : numbers) {
            tasks.add(() -> {
                int count=0;
                int y=x;
                do {
                    if (y % 10 == digit) {
                        count++;
                    }
                    y /= 10;
                } while (y > 0);
                return count;
            });
        }
        ExecutorService service = Executors.newFixedThreadPool(10);
        int answer=0;
        try {
            List<Future<Integer>> results = service.invokeAll(tasks);
            for (Future<Integer> result : results) {
                try {
                    answer+=result.get();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return answer;
    }
}

参考博客:
https://www.cnblogs.com/micrari/p/5634447.html
https://blog.csdn.net/darrensun2014/article/details/51073810

小结

Fork/Join框架充分利用了线程进行并行计算,减少了线程间的竞争;
Executor框架的最大优点是把任务的提交和执行解耦。要执行任务的人只需把Task描述清楚,提交即可,至于Task怎么被执行则无需关心;
这些框架是很好的设计方案,在遇到具体问题时,可以参考并应用这些

猜你喜欢

转载自blog.csdn.net/Francis123580/article/details/80638901
今日推荐