Fork / Join 框架
Fork/Join框架是Java7提供的用于并行执行任务的框架
是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架
框架设计
- 分割任务
- 执行任务,合并结果
代码实例
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怎么被执行则无需关心;
这些框架是很好的设计方案,在遇到具体问题时,可以参考并应用这些