互联网一直在说和提到高并发,那什么是高并发,怎么处理高并发?也许每个人都有自己的见解和应对方法,但是总体思想应该及相同的,分而治之,单个服务不发满足时增加服务集群,集群无法满足时考虑拆分,同时选择合适的算法,最终达到解决高并发,但是什么样的级别才能算是高呢?不同的业务也许需求不一样,但是大致还都是相同的,我们最开始使用的处理要素是,200并发,200请求/秒,单机,并且后台也许会有不同的业务逻辑,也许会有其他的复杂计算,这个是根据不同的系统不同的业务而不同设计的。业务你的并发达不到这么高,根据数据的要求,你可能会想到异步处理,或者消息处理来增加并发数。所有的解决方案都不是相同的,只选择适合你们业务的解决方案。
言归正传,这里我们讲的是fork/join的并发处理框架,该框架是是在jdk1.7出现的,如果有人接触过hadoop中的mapreduce,思想是相同的。说起fork/join,我们首先看下该思想的执行操作线路图,这样可以更好的理解该并行计算框架。
上面的图解中有两个最大的世界,fork:将大任务拆分成小任务进行执行;join:将fork出来的小任务的执行结果进行合并,最终实现过程拆分结果合并的操作。
先上说明一些主要的类:ForkJoinTask:顶层设计类,主要是对任务的拆分合并的计算架构。该顶层类有两个核心子类,在java中也是主要继承这两个类来实现并行计算。RecursiveAction:从后缀也可以猜测出,该执行只是动作的执行,没有返回结果。RecursiveTask:执行任务,有返回值,并且是指定类型的返回结果。ForkJoinPool:任务执行线程池,根据自身算法实现线程的高度复用及任务优化。
下面从demo中解析:无返回值的操作
public class ObjectTest {
public static void main(String[] args) throws InterruptedException {
//创建执行线程池
ForkJoinPool pool = new ForkJoinPool();
//提交任务
pool.submit(new ActionTest(0, 200));
pool.awaitTermination(3, TimeUnit.SECONDS);
pool.shutdown();
}
}
//继承无返回值的任务
class ActionTest extends RecursiveAction {
private static final int MAX = 50;
private int start;
private int end;
public ActionTest(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if ((end - start) < MAX) {
System.out.println(Thread.currentThread().getName() + "--" + start + "==" + end);
} else {
int middle = (start + end) / 2;
ActionTest up = new ActionTest(start, middle);
ActionTest down = new ActionTest(middle, end);
//继续拆分
up.fork();
down.fork();
}
}
}
源码中的提现:
public class ForkJoinPool extends AbstractExecutorService ,该源码中涉及到很多线程安全和线程池的概念,源码比较多,这里就不一一说明,后面有时间了会拿出来单独说明。
public abstract class RecursiveTask extends ForkJoinTask {
private static final long serialVersionUID = 5232453952276485270L;
/**
* The result of the computation.
*/
V result;
/**
* The main computation performed by this task.
*/
protected abstract V compute();
public final V getRawResult() {
return result;
}
protected final void setRawResult(V value) {
result = value;
}
/**
* Implements execution conventions for RecursiveTask.
*/
protected final boolean exec() {
result = compute();
return true;
}
}
该源码很简单,只是对父类的继承,操作的结果是无返回值的,所以有两个方法直接操作返回,主要提供抽象的compute()方法供子类实现。
有返回值的demo:
public class ObjectTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建执行线程池
ForkJoinPool pool = new ForkJoinPool();
//提交任务
Future futuer = pool.submit(new TaskTest(0, 200));
System.out.println(futuer.get());
pool.awaitTermination(3, TimeUnit.SECONDS);
pool.shutdown();
}
}
class TaskTest extends RecursiveTask {
private static final int MAX = 50;
private int start;
private int end;
public TaskTest(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
if ((end - start) < MAX) {
for (int i = start; i < end; i++) {
sum += i;
}
return sum;
} else {
int middle = (start + end) / 2;
TaskTest up = new TaskTest(start, middle);
TaskTest down = new TaskTest(middle, end);
//继续拆分
up.fork();
down.fork();
return up.join() + down.join();
}
}
}
主要区别在继承的父类和返回值,提现在join方法上。
源码体现:
public abstract class RecursiveTask extends ForkJoinTask {
private static final long serialVersionUID = 5232453952276485270L;
/**
* The result of the computation.
*/
V result;
/**
* The main computation performed by this task.
*/
protected abstract V compute();
public final V getRawResult() {
return result;
}
protected final void setRawResult(V value) {
result = value;
}
/**
* Implements execution conventions for RecursiveTask.
*/
protected final boolean exec() {
result = compute();
return true;
}
}
主要在返回值上的设置会获取
这里先做简单的演示,后面再做深层次的解析和分析