/**
*
* 功能描述:
*
* @param: 通过fork/join 进行求合计算
* @return:
* @auther: csh
* @date: 2023/4/17 9:52 下午
*/
public class ArraySum extends RecursiveTask {
private static final int THRESHOLD = 1000; // 阈值,当数组大小小于该值时不再进行拆分
private long[] arr;
private int start;
private int end;
public ArraySum(long[] arr, int start, int end) {
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) { // 如果数组大小小于阈值,直接计算
long sum = 0L;
for (int i = start; i < end; i++) {
sum += arr[i];
}
return sum;
} else { // 如果数组大小大于阈值,拆分为两个任务并执行
int mid = (start + end) / 2;
ArraySum left = new ArraySum(arr, start, mid);
ArraySum right = new ArraySum(arr, mid, end);
left.fork();
right.fork();
return left.join() + right.join();
}
}
public static void main(String[] args) {
int N = 100000;
long[] arr = new long[N];
for (int i = 0; i < N; i++) {
arr[i] = i;
}
ForkJoinPool pool = new ForkJoinPool();
long sum = pool.invoke(new ArraySum(arr, 0, arr.length));
System.out.println("累加起来的结果是: " + sum);
}
}
结果
相加起来的结果是: 4999950000
fork/join的源码学习
ForkJoinTask 主要利用了 Unsafe 类的 CAS 操作实现了对任务状态的更新。在执行完成任务时,调用 onCompletion(CountedCompleter caller) 方法通知该任务的依赖任务或向等待该任务的线程发送信号,以此实现对任务结果的合并和传递。
属性:
static final int REOPR_SIGNAL: 表示任务的初始状态,即等待被执行。
static final int DONE_MASK: 任务完成状态的标识。
static final int NORMAL: 任务正常完成。
static final int CANCELLED: 任务被取消。
static final int EXCEPTIONAL: 任务发生异常。
volatile int status: 表示任务的状态,取值可能为 REOPR_SIGNAL、NORMAL、CANCELLED 或 EXCEPTIONAL 中的一个。
volatile ForkJoinTask> next: 指向下一个等待执行的任务。
volatile Thread runner: 执行该任务的线程。
final short statusFlags: 表示任务的状态及其他一些控制信息。
final short mode: 表示任务的运行模式。
Throwable exception: 任务执行过程中发生异常时,保存该异常对象。
方法:
public final void fork(): 将该任务加入到当前工作线程队列中,等待被执行。
public final boolean isDone(): 判断该任务是否已完成。
public final boolean cancel(boolean mayInterruptIfRunning): 取消该任务的执行。
public final void completeExceptionally(Throwable ex): 异常完成该任务,并将发生的异常传递给等待该任务的线程。
protected abstract void compute(): 子类必须实现的计算方法,用于执行具体的任务逻辑。
public final void quietlyCompleteRoot(): 安静地完成该任务,并通知等待该任务的线程。如果该任务是根任务,则将结果放到 ForkJoinPool 中的队列中。
public final int getQueuedTaskCount(): 获取等待执行的任务个数。
public final boolean isCancelled(): 判断该任务是否已取消。
public final boolean isCompletedAbnormally(): 判断该任务是否发生异常。
public final boolean isCompletedNormally(): 判断该任务是否正常完成。
public final Throwable getException(): 获取该任务发生的异常。
public final ForkJoinTask submit(): 将该任务提交到 ForkJoinPool 中执行,并返回该任务的结果。
public final V invoke(): 在当前线程中执行该任务,并返回该任务的结果。
public static void invokeAll(ForkJoinTask> t1, ForkJoinTask> t2): 执行给定的两个任务,并等待这两个任务都完成。
public static void invokeAll(ForkJoinTask... tasks): 执行指定的一组任务,并等待所有任务都完成。
protected static void reportException(Throwable ex): 抛出给定的异常。
私有方法:
final int setCompletion(int completion): 原子性地将该任务的状态修改为完成状态,同时返回原状态值。
final int doExec(): 执行当前任务的 compute() 方法,并返回任务的状态值。
final boolean trySetSignal(): 尝试将当前任务的状态从新建转换为信号状态 REOPR_SIGNAL。
static void internalPropagateException(Throwable ex): 尝试将给定的异常对象抛出到外层任务。
package java.util.concurrent;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.reflect.Constructor;
//为抽象类必须被实现,实现Future
public abstract class ForkJoinTask implements Future, Serializable {
/** 状态:初始状态:status = SIGNAL
正常完成状态:status = NORMAL
取消状态:status = CANCELLED
异常状态:status = EXCEPTIONAL */
volatile int status; // accessed directly by pool and workers
static final int DONE_MASK = 0xf0000000; // 任务完成时的标识。
static final int NORMAL = 0xf0000000; // 正常任务状态。
static final int CANCELLED = 0xc0000000; // 取消状态。
static final int EXCEPTIONAL = 0x80000000; // 异常状态。
static final int SIGNAL = 0x00010000; // 初始状态 必须为 >= 1 << 16
static final int SMASK = 0x0000ffff; // 低位掩码,也是最大索引位
/**
* 原子性地将该任务的状态修改为完成状态,同时返回原状态值。
入参为状态
*/
private int setCompletion(int completion) {
for (int s;;) {
if ((s = status) < 0)
return s;
if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
if ((s >>> 16) != 0)
synchronized (this) { notifyAll(); }
return completion;
}
}
}
/**
*执行当前任务的 compute() 方法,并返回任务的状态值。
*/
final int doExec() {
int s; boolean completed;
//状态大于0
if ((s = status) >= 0) {
try {
//立即执行任务
completed = exec();
} catch (Throwable rex) {
return setExceptionalCompletion(rex);
}
//执行后状态判断
if (completed)
//设置状态为正常任务状态。
s = setCompletion(NORMAL);
}
//返回状态
return s;
}
/**
* 在等待该任务完成时,使用指定的超时时间来阻塞当前线程。
*/
final void internalWait(long timeout) {
int s;
//正常状态才继续
if ((s = status) >= 0 && // force completer to issue notify
//又是Unsafe 的cas来更改状态
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
//同步块
synchronized (this) {
//状态大于0 正常 等待timeout时间
if (status >= 0)
try { wait(timeout); } catch (InterruptedException ie) { }
else
//唤醒所有任务
notifyAll();
}
}
}
/**
* 阻止非工作线程,直到完成。
*/
private int externalAwaitDone() {
//判断类型获取池中的状态
int s = ((this instanceof CountedCompleter) ? // try helping
ForkJoinPool.common.externalHelpComplete(
(CountedCompleter>)this, 0) :
ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
//大于0证明不是初始化及已结束
if (s >= 0 && (s = status) >= 0) {
boolean interrupted = false;
do {
//通过循环方式进行cas设置锁
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0) {
try {
wait(0L);
} catch (InterruptedException ie) {
interrupted = true;
}
}
else
notifyAll();
}
}
} while ((s = status) >= 0);
//中断状态为true(有可能结束或异常了)
if (interrupted)
//进行当前线程中断
Thread.currentThread().interrupt();
}
//反回状态
return s;
}
/**
* 等待该任务完成,并允许在等待的过程中中断当前线程。
该方法通过调用 LockSupport.park(this) 方法来实现线程等待,如果当前线程被中断,则会抛出 InterruptedException 异常。
*/
private int externalInterruptibleAwaitDone() throws InterruptedException {
int s;
//中断线程成功 直接抛出
if (Thread.interrupted())
throw new InterruptedException();
//如果状态大于0 且 尝试通过线程池进行执行所有任务 证明正常
if ((s = status) >= 0 &&
(s = ((this instanceof CountedCompleter) ?
ForkJoinPool.common.externalHelpComplete(
(CountedCompleter>)this, 0) :
ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
0)) >= 0) {
//循环进行状态置为初始化
while ((s = status) >= 0) {
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
wait(0L);
else
notifyAll();
}
}
}
}
return s;
}
/**
* 等待该任务完成,并返回任务的状态。
在等待任务完成的过程中,使用自旋锁的方式不断地检查任务状态。
如果任务状态为完成状态,则返回该任务的状态;否则,使用 LockSupport.park(this) 方法挂起当前线程,并等待任务完成。
注意:这个方法在等待过程中由于使用了自旋锁和线程挂起的方式,因此可能会消耗大量的 CPU 资源。
*
*/
private int doJoin() {
//参数声名 状态:s 线程:t 工作线程:wt 工作队列:w
int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
//获取状态如果小于0 当前线程中断 否则进行结束
return (s = status) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(w = (wt = (ForkJoinWorkerThread)t).workQueue).
tryUnpush(this) && (s = doExec()) < 0 ? s :
wt.pool.awaitJoin(w, this, 0L) :
externalAwaitDone();
}
/**
* 在当前线程中执行该任务,并返回任务的状态值(同上类似)
*/
private int doInvoke() {
int s; Thread t; ForkJoinWorkerThread wt;
return (s = doExec()) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(wt = (ForkJoinWorkerThread)t).pool.
awaitJoin(wt.workQueue, this, 0L) :
externalAwaitDone();
}
// Exception table support
//任务异常列表
private static final ExceptionNode[] exceptionTable;
//任务异常重入锁
private static final ReentrantLock exceptionTableLock;
//存放异常的实例
private static final ReferenceQueue
创建Web工程,使用eclipse ee创建maven web工程 1.右键项目,选择Project Facets,点击Convert to faceted from 2.更改Dynamic Web Module的Version为2.5.(3.0为Java7的,Tomcat6不支持). 如果提示错误,可能需要在Java Compiler设置Compiler compl
最近一直在看python的document,打算在基础方面重点看一下python的keyword、Build-in Function、Build-in Constants、Build-in Types、Build-in Exception这四个方面,其实在看的时候发现整个《The Python Standard Library》章节都是很不错的,其中描述了很多不错的主题。先把Build-in Fu
学习函数式编程
package base;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
// Integer a = 4;
// Double aa = (double)a / 100000;
// Decimal
Java中的泛型的使用:1.普通的泛型使用
在使用类的时候后面的<>中的类型就是我们确定的类型。
public class MyClass1<T> {//此处定义的泛型是T
private T var;
public T getVar() {
return var;
}
public void setVa