在看 ConcurrentHashMap 的源码时,BulkTask extends CountedCompleter,CountedCompleter extends ForkJoinTask,那么我们也按照这个继承顺序,一探究竟。
1. invoke 看 ForkJoinTask 的各种状态值
- 实体类
import java.util.concurrent.CountedCompleter;
public class MyForkJoinTask<R> extends CountedCompleter<R> {
static int i = 1;
public MyForkJoinTask() {
}
@Override
public void compute() {
try {
/* 特定的设置为 EXCEPTIONAL */
if(i == 2) completeExceptionally(new Exception());
} catch (Exception e) {
e.printStackTrace();
}
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/* 不让 SIGNAL 设置完成*/
if(i != 5) propagateCompletion();
}
}
- 测试类
import java.lang.reflect.Field;
public class MyForkJoinTaskTest01 {
public static void main(String[] args) throws Exception {
MyForkJoinTask<Object> myForkJoinTask01 = new MyForkJoinTask<>();
MyForkJoinTask<Object> myForkJoinTask02 = new MyForkJoinTask<>();
MyForkJoinTask<Object> myForkJoinTask03 = new MyForkJoinTask<>();
MyForkJoinTask<Object> myForkJoinTask04 = new MyForkJoinTask<>();
MyForkJoinTask<Object> myForkJoinTask05 = new MyForkJoinTask<>();
MyForkJoinTask<Object> myForkJoinTask06 = new MyForkJoinTask<>();
Field status01 = myForkJoinTask01.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
Field status02 = myForkJoinTask02.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
Field status03 = myForkJoinTask03.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
Field status04 = myForkJoinTask04.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
Field status05 = myForkJoinTask05.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
Field status06 = myForkJoinTask06.getClass().getSuperclass().getSuperclass().getDeclaredField("status");
status01.setAccessible(true);
status02.setAccessible(true);
status03.setAccessible(true);
status04.setAccessible(true);
status05.setAccessible(true);
status06.setAccessible(true);
new Thread(() -> {
try {
Thread.sleep(500);
System.out.println("=================");
myForkJoinTask01.cancel(true);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
try{
/* 半路取消,CANCELLED */
myForkJoinTask01.invoke();
} catch (Exception e) {
e.printStackTrace();
}
try{
/* 直接取消,CANCELLED */
myForkJoinTask02.cancel(true);
} catch (Exception e) {
e.printStackTrace();
}
try{
/* 设置成 EXCEPTIONAL */
myForkJoinTask03.invoke();
} catch (Exception e) {
e.printStackTrace();
}
try{
/* 正常执行完成 */
myForkJoinTask04.invoke();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("================ myForkJoinTask01 ================");
System.out.print("status: " + Integer.toHexString((Integer) status01.get(myForkJoinTask01)) + "\t CANCELLED = 0xc0000000"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask01.isCancelled() + " \t");
System.out.print("isDone(): " + myForkJoinTask01.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask01.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask01.isCompletedNormally() + "\t");
System.out.println();
System.out.println("================== myForkJoinTask02 ===================");
System.out.print("status: " + Integer.toHexString((Integer) status02.get(myForkJoinTask02)) + "\t CANCELLED = 0xc0000000"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask02.isCancelled() + "\t");
System.out.print("isDone(): " + myForkJoinTask02.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask02.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask02.isCompletedNormally() + "\t");
System.out.println();
System.out.println("================= myForkJoinTask03 ====================");
System.out.print("status: " + Integer.toHexString((Integer) status03.get(myForkJoinTask03)) + "\t EXCEPTIONAL = 0x80000000;"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask03.isCancelled() + "\t");
System.out.print("isDone(): " + myForkJoinTask03.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask03.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask03.isCompletedNormally() + "\t");
System.out.println();
System.out.println("================= myForkJoinTask04 ====================");
System.out.print("status: " + Integer.toHexString((Integer) status04.get(myForkJoinTask04)) + "\t NORMAL = 0xf0000000;"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask04.isCancelled() + "\t");
System.out.print("isDone(): " + myForkJoinTask04.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask04.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask04.isCompletedNormally() + "\t");
System.out.println();
System.out.println("================= myForkJoinTask05 ====================");
System.out.print("status: " + Integer.toHexString((Integer) status05.get(myForkJoinTask05)) + "\t 初始化 status = 0;"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask05.isCancelled() + "\t");
System.out.print("isDone(): " + myForkJoinTask05.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask05.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask05.isCompletedNormally() + "\t");
System.out.println();
System.out.println("=============================================");
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("================= myForkJoinTask06 ====================");
System.out.print("status: " + Integer.toHexString((Integer) status06.get(myForkJoinTask06)) + "\t SIGNAL = 0x00010000;"+ "\t");
System.out.print("isCancelled(): " + myForkJoinTask06.isCancelled() + "\t");
System.out.print("isDone(): " + myForkJoinTask06.isDone() + "\t");
System.out.print("isCompletedAbnormally(): " + myForkJoinTask06.isCompletedAbnormally() + "\t");
System.out.print("isCompletedNormally(): " + myForkJoinTask06.isCompletedNormally() + "\t");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
try{
/* invoke 执行 */
System.out.println("myForkJoinTask06 开始执行");
myForkJoinTask06.invoke();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 为什么使用 invoke(),而不直接使用 compute() ?
- 先说结论,invoke() 会等待全部任务完成,compute()执行完当前任务则退出。
- 实体类
import java.util.concurrent.CountedCompleter;
public class MyForkJoinTask02<R> extends CountedCompleter<R> {
int batch = 0;
public MyForkJoinTask02(CountedCompleter<?> completer, int batch) {
super(completer);
this.batch = batch;
}
@Override
public void compute() {
for (;batch > 0;) {
addToPendingCount(1);
new MyForkJoinTask02<R>(this, batch >>>= 1).fork();
}
System.out.println("now batch = " + batch);
propagateCompletion();
}
}
- 测试类
public class MyForkJoinTaskTest02 {
public static void main(String[] args) throws InterruptedException {
MyForkJoinTask02<Object> myForkJoinTask = new MyForkJoinTask02<>(null, 5);
MyForkJoinTask02<Object> myForkJoinTask02 = new MyForkJoinTask02<>(null, 5);
myForkJoinTask.invoke();
System.out.println("========== 华丽分割线 =========");
myForkJoinTask02.compute();
System.out.println("===========================");
myForkJoinTask02.join();
}
}
3. 异常存储之 exceptionTable
- 实体类
package cn.cerish.forkJoin;
import java.util.concurrent.CountedCompleter;
public class MyForkJoinTask03<R> extends CountedCompleter<R> {
static int i = 0;
int batch;
public MyForkJoinTask03(CountedCompleter<?> completer, int batch) {
super(completer);
this.batch = batch;
}
/* 抛出不同种类的错误 */
@Override
public void compute() {
i++;
if(i == 1) completeExceptionally(new RuntimeException());
if(i == 2) completeExceptionally(new NoSuchFieldException());
if(i == 3) completeExceptionally(new IndexOutOfBoundsException());
}
}
- 测试类
import java.lang.reflect.Field;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class MyForkJoinTaskTest03 {
public static void main(String[] args) throws Exception {
MyForkJoinTask03<String> myForkJoinTask01 = new MyForkJoinTask03<>(null, 1);
MyForkJoinTask03<String> myForkJoinTask02 = new MyForkJoinTask03<>(null, 1);
MyForkJoinTask03<String> myForkJoinTask03 = new MyForkJoinTask03<>(null, 1);
MyForkJoinTask03<String> myForkJoinTask04 = new MyForkJoinTask03<>(null, 1);
Class<?> forkJoinTaskClass = myForkJoinTask01.getClass().getSuperclass().getSuperclass();
Field exceptionTable = forkJoinTaskClass.getDeclaredField("exceptionTable");
exceptionTable.setAccessible(true);
try{
myForkJoinTask01.invoke();
} catch (Exception e) {
e.printStackTrace();
}
try{
myForkJoinTask02.invoke();
} catch (Exception e) {
e.printStackTrace();
}
try{
myForkJoinTask03.invoke();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("====================== myForkJoinTask01 ====================");
System.out.println("getException(): " + myForkJoinTask01.getException() + "\t");
System.out.print("getCompleter(): " + myForkJoinTask01.getCompleter() + "\t");
System.out.print("getForkJoinTaskTag(): " + myForkJoinTask01.getForkJoinTaskTag() + "\t");
System.out.print("getPendingCount(): " + myForkJoinTask01.getPendingCount() + "\t");
System.out.print("getRawResult(): " + myForkJoinTask01.getRawResult() + "\t");
System.out.println();
System.out.println("====================== myForkJoinTask02 ====================");
System.out.println("getException(): " + myForkJoinTask02.getException() + "\t");
System.out.print("getCompleter(): " + myForkJoinTask02.getCompleter() + "\t");
System.out.print("getForkJoinTaskTag(): " + myForkJoinTask02.getForkJoinTaskTag() + "\t");
System.out.print("getPendingCount(): " + myForkJoinTask02.getPendingCount() + "\t");
System.out.print("getRawResult(): " + myForkJoinTask02.getRawResult() + "\t");
System.out.println();
System.out.println("===================== myForkJoinTask03 =======================");
System.out.println("getException(): " + myForkJoinTask03.getException() + "\t");
System.out.print("getCompleter(): " + myForkJoinTask03.getCompleter() + "\t");
System.out.print("getForkJoinTaskTag(): " + myForkJoinTask03.getForkJoinTaskTag() + "\t");
System.out.print("getPendingCount(): " + myForkJoinTask03.getPendingCount() + "\t");
System.out.print("getRawResult(): " + myForkJoinTask03.getRawResult() + "\t");
System.out.println();
System.out.println("=============== myForkJoinTask04 用来查看 exceptionTable ===============");
Object[] objects = (Object[]) exceptionTable.get(myForkJoinTask04);
for (Object object : objects) {
if(object != null) System.out.println(object);
}
myForkJoinTask03.reinitialize();
System.out.println("=============== myForkJoinTask03.reinitialize() 清除错误状态 ===============");
Object[] objects01 = (Object[]) exceptionTable.get(myForkJoinTask04);
for (Object object : objects01) {
if(object != null) System.out.println(object);
}
}
}
4. ForkJoinTask 中的 Runnable、Callable
import java.util.concurrent.ForkJoinTask;
public class MyForkJoinTaskTest04 {
public static void main(String[] args) throws Exception {
ForkJoinTask<?> adapt01 = ForkJoinTask.adapt(() -> {
System.out.println("I am Runnable(), 我的返回值默认为null即没有返回值");
});
System.out.println("adapt01.invoke(): " + adapt01.invoke());
System.out.println("================== 华丽分割线 ====================");
ForkJoinTask<Integer> adapt02 = ForkJoinTask.adapt(() -> {
System.out.println("I am Runnable(), 在下是有返回值的");
}, 100);
System.out.println("adapt02.invoke(): " + adapt02.invoke());
System.out.println("================== 华丽分割线 ====================");
ForkJoinTask<String> adapt03 = ForkJoinTask.adapt(() -> {
System.out.println("I am Callable(), 在下是有返回值的,直接方法内返回");
return "I am return value for Callable()";
});
System.out.println("adapt03.invoke(): " + adapt03.invoke());
}
}