参考
Stream并行计算原理:
https://redspider.gitbook.io/concurrent/di-san-pian-jdk-gong-ju-pian/19
Stream API并行流与串行流对比试验:
https://blog.csdn.net/TimHeath/article/details/71366448
demo
自己的实验对比发现:
同样的计算任务fork框架时间>parallerStream>stream串行流 ≈ 无stream的单线程
同时,Fork/join框架非常容易出错。
三种计算的源码:
public class Calculator {
public static Long calcBillAmount(BillCalculateContext calculateContext)
throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
List<CalculateTask> calculateTasks = preHandle(calculateContext);
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
Long sum = 0L;
for (CalculateTask calculateTask : calculateTasks) {
ForkJoinTask<Long> taskSum = forkJoinPool.submit(calculateTask);
sum += taskSum.get();
}
long endTime = System.currentTimeMillis();
System.out.println("Time : " + String.valueOf(endTime - startTime));
return sum;
}
public static Long calcBillAmountParallel(BillCalculateContext calculateContext)
throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
List<CalculateUnit> calculateUnits = new ArrayList<>();
Long result = 0L;
for (Rateable resource : calculateContext.getResources()) {
Long sum = 0L;
List<Calculable> calculableLists = calculateContext.getTaskList().parallelStream().filter(calculable -> {
return calculable.time() < resource.boundary().upper() && calculable.time() > resource.boundary()
.lower();
}).collect(Collectors.toList());
sum += calculableLists.parallelStream().mapToLong(calculable -> {
return calculable.num() * calculable.time();
}).sum();
result += sum * resource.price();
}
long endTime = System.currentTimeMillis();
System.out.println("Time : " + String.valueOf(endTime - startTime));
return result;
}
public static Long calcBillAmountSingleThread(BillCalculateContext calculateContext) {
long startTime = System.currentTimeMillis();
List<CalculateTask> calculateTasks = preHandle(calculateContext);
Long sum = 0L;
for (CalculateTask calculateTask : calculateTasks) {
for (Calculable calculable : calculateTask.tasks) {
sum += calculable.num() * calculable.time() * calculateTask.rate;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Time : " + String.valueOf(endTime - startTime));
return sum;
}
private static List<CalculateTask> preHandle(BillCalculateContext calculateContext) {
// 拆分:根据费率拆分TaskList,每个list内的费率是个常量
List<CalculateUnit> calculateUnits = CalculateUnit.buildCalculateUnit(calculateContext);
List<CalculateTask> calculateTasks = new ArrayList<>();
for (CalculateUnit calculateUnit : calculateUnits) {
calculateTasks.add(new CalculateTask(calculateUnit.getTaskList(), calculateUnit.getRate()));
}
return calculateTasks;
}
@Getter
private static class CalculateUnit {
private final List<Calculable> taskList;
private final Long rate;
CalculateUnit(List<Calculable> taskList, Long rate) {
this.taskList = taskList;
this.rate = rate;
}
static List<CalculateUnit> buildCalculateUnit(BillCalculateContext billCalculateContext) {
List<CalculateUnit> calculateUnits = new ArrayList<>();
for (Rateable resource : billCalculateContext.getResources()) {
List<Calculable> calculableLists = billCalculateContext.getTaskList()
.stream()
.filter(calculable -> calculable.time() < resource.boundary().upper())
.collect(Collectors.toList());
calculateUnits.add(new CalculateUnit(calculableLists, resource.price()));
}
return calculateUnits;
}
}
private static class CalculateTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 2;
private static final Long serialVersionUID = -79642431985841520L;
private List<Calculable> tasks = new ArrayList<>();
private final Long rate;
CalculateTask(List<Calculable> tasks, Long rate) {
this.rate = rate;
this.tasks = tasks;
}
@Override
protected Long compute() {
AtomicReference<Long> sum = new AtomicReference<>(0L);
if (tasks.size() < THRESHOLD) {
tasks.stream().forEach(calculable -> sum.updateAndGet(v -> v + (calculable.time() * calculable.num())));
// tasks.stream().forEach(calculable -> sum.set(sum.get() + (calculable.time() * calculable.num())));
} else {
int middle = tasks.size() / 2;
CalculateTask leftTask = new CalculateTask(tasks.subList(0, middle), rate);
CalculateTask rightTask = new CalculateTask(tasks.subList(middle, tasks.size()), rate);
leftTask.fork();
rightTask.fork();
Long leftResult = leftTask.join();
Long rightResult = rightTask.join();
sum.set(sum.get() + leftResult + rightResult);
}
return sum.get() * rate;
}
}
}
// --------------------------------------------------
//Test:
public class CalculatorTest {
private static class InnerCalculable implements Calculable {
private final long num;
private final long time;
public InnerCalculable(long num, long time) {
this.num = num;
this.time = time;
}
@Override
public long num() {
return num;
}
@Override
public long time() {
return time;
}
@Override
public ResourceEnum getResourceType() {
return null;
}
}
private static class InnerRateable implements Rateable {
private final long price;
private final InnerBoundary innerBoundary;
public InnerRateable(long price, InnerBoundary innerBoundary) {
this.price = price;
this.innerBoundary = innerBoundary;
}
@Override
public long price() {
return price;
}
@Override
public Boundary<Long> boundary() {
return innerBoundary;
}
}
private static class InnerBoundary implements Boundary<Long> {
private final Long lower;
private final Long upper;
public InnerBoundary(Long lower, Long upper) {
this.lower = lower;
this.upper = upper;
}
@Override
public Long lower() {
return lower;
}
@Override
public Long upper() {
return upper;
}
@Override
public Boundary<Long> calcBoundary(List<Pair<Long, Long>> tPairs) {
return null;
}
}
static List<Calculable> taskList = new ArrayList<>();
static List<Rateable> resources = new ArrayList<>();
@BeforeClass
public static void setUp() throws Exception {
for (int i = 0; i < 1000000; i++) {
taskList.add(new InnerCalculable(100L, 1L));
}
resources.add(new InnerRateable(1L, new InnerBoundary(0L, 100L)));
}
@Test
public void calcBillAmount() throws Exception {
CalculateContext CalculateContext = new CalculateContext(taskList, resources);
Long sum = Calculator.calcBillAmount(billCalculateContext);
System.out.println(sum);
}
@Test
public void calcBillAmountSingleThread() throws Exception {
BillCalculateContext billCalculateContext = new BillCalculateContext(taskList, resources);
Long sum = BillCalculator.calcBillAmountSingleThread(billCalculateContext);
System.out.println(sum);
}
@Test
public void calcBillAmountParallel() throws Exception {
BillCalculateContext billCalculateContext = new BillCalculateContext(taskList, resources);
Long sum = BillCalculator.calcBillAmountParallel(billCalculateContext);
System.out.println(sum);
}
}