最近看多线程方面的知识,无意间看到fork/join框架,蛮有意思的,就研究了下,记录下来以便以后查询
Fork/Join框架是jdk1.7之后concurrent包新增的功能
简单来说,实现了一个任务队列,每个任务可以自己选择拆分当前任务并添加到任务队列中,线程池中空闲的线程会主动执行任务队列中的任务,当然ForkJoinPool类肯定不会如此简单的设计,但大体上的功能就是如此,具体如何设计的,比如避免线程争用死锁等等需要查看源码研究
先看一个例子
public static final ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<>();
public static final AtomicInteger integer = new AtomicInteger(0);
public static final AtomicInteger result = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>(100000);
for (int i = 0; i < 100000; i++) {
list.add("index:" + i);
}
//此处新建fork任务
ForkJoinPool pool = new ForkJoinPool();
//提交任务
pool.execute(new MyTask(list));
//pool.awaitTermination(1, TimeUnit.DAYS);
//关闭fork(会执行完现有任务)
pool.shutdown();
//awaitTermination见描述
pool.awaitTermination(1, TimeUnit.DAYS);
System.out.println(set.size());
System.out.println(integer.get());
System.out.println(result.get());
set.forEach(str -> {
System.out.println(str);
});
}
static class MyTask extends RecursiveAction {
private List<String> list;
public MyTask(List<String> list) {
this.list = list;
}
@Override
protected void compute() {
if (list == null) {
return;
}
// 队列大于100时分为两个任务来执行
if (list.size() > 100) {
RecursiveAction left = new MyTask(list.subList(0, 100));
RecursiveAction right = new MyTask(list.subList(100, list.size()));
left.fork();
right.fork();
} else {
list.forEach(str -> {
result.getAndIncrement();
});
integer.getAndIncrement();
set.add(Thread.currentThread().getName());
}
}
}
new ForkJoinPool()直接新建forkjoinpool,如果不指定线程数量,系统会自动设置线程数,也可以指定线程数直接传入构造方法即可new ForkJoinPool(4)最多4个线程执行任务
execute方法执行没有返回值的任务,submit执行有返回值得任务,这两个方法都接受ForkJoinTask的参数,我们写代码时可以直接使用ForkJoinTask的子类RecursiveAction/RecursiveTask来实现具体的方法,只需要实现compute方法即可,具体实现可以参考上面的例子
需要注意的是ForkJoinPool execute和submit方法只是提交执行,是子线程执行,因此有没有执行完,需要使用awaitTermination方法,该方法是阻塞方法会在ForkJoinPool被关闭(方法执行完关闭命令才有效)或者线程被打断或者超时时才会继续执行下面的代码(对于有返回值得RecursiveTask任务,可以直接调用RecursiveTask中的get方法来阻塞代码等待任务执行完毕)