Java多线程——ForkJoin初步认识及基本使用

概述

也是刚接触ForkJoin,简单记录一下,纯属初体验

Fork/Join是JDK1.7加入的新的线程池实现,其体现的是一种分治思想,适用于能够进行任务拆分的CPU密集型运算(默认创建与CPU核心数相同大小的线程池,由于是CPU密集型运算,线程池大小超过CPU核心数没有什么意义)。

Fork/Join在分治的基础上加入了多线程,可以把每个任务分解和合并交给不同的线程来完成,进一步的提高运算效率。

示例

这是一个计算1-n之间所有整数相加的demo,总体来说所谓的分治思想,类似于递归,将1-n整数相加的操作,分解为【1】、【2+1】、【3+(2+1)】、【4+(3+2+1)】、【5+(4+3+2+1)】,然后用线程池中的不同线程分别计算,最终合并结果

package com.leolee.multithreadProgramming.threadPool.forkJoin;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinTest
 * @Description: TODO
 * @Author LeoLee
 * @Date 2021/3/3
 * @Version V1.0
 **/
public class ForkJoinTest {

    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();//无参的构造函数默认创建的是CPU核心数大小的线程池
        System.out.println(forkJoinPool.invoke(new MyTask(5)));

        //分治的思想体现在:new MyTask(5) + new MyTask(4) + new MyTask(3) + new MyTask(2) + new MyTask(1)
    }

}

/*
 * 功能描述: <br>
 * 〈特殊的任务,并非是Thread或者是Runnable〉
 *  RecursiveTask是带返回结果的任务,RecursiveAction无返回结果
 * @Param:
 * @Return: 1-n之间整数的和
 * @Author: LeoLee
 * @Date: 2021/3/3 21:28
 */
@Slf4j
class MyTask extends RecursiveTask<Integer> {

    private int n;

    public MyTask(int n) {
        this.n = n;
    }

    //重写toString方便打印运算过程
    @Override
    public String toString() {
        return "MyTask{" +
                "n=" + n +
                '}';
    }

    //此过程就是类似于递归
    @Override
    protected Integer compute() {
        //终止条件
        if (n == 1) {
            log.info("join() {}", n);
            return 1;
        }

        MyTask t1 = new MyTask(n - 1);
        t1.fork();//让一个线程去执行此任务
        log.info("fork() {} + {}", n, t1.toString());

        int t1Result = t1.join();//获取任务的执行结果
        int result = n + t1Result;
        log.info("join() {} + {} = {}", n, t1.toString(), result);
        return result;
    }
}

运行结果:
21:50:57.021 [ForkJoinPool-1-worker-3] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() 3 + MyTask{n=2}
21:50:57.021 [ForkJoinPool-1-worker-1] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() 5 + MyTask{n=4}
21:50:57.021 [ForkJoinPool-1-worker-4] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() 2 + MyTask{n=1}
21:50:57.021 [ForkJoinPool-1-worker-2] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() 4 + MyTask{n=3}
21:50:57.021 [ForkJoinPool-1-worker-5] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 1
21:50:57.040 [ForkJoinPool-1-worker-4] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 2 + MyTask{n=1} = 3
21:50:57.041 [ForkJoinPool-1-worker-3] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 3 + MyTask{n=2} = 6
21:50:57.041 [ForkJoinPool-1-worker-2] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 4 + MyTask{n=3} = 10
21:50:57.041 [ForkJoinPool-1-worker-1] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 5 + MyTask{n=4} = 15
15

上述示例有个问题,虽然是不同的线程执行了各自的任务,但是每个线程都依赖于下一个线程的计算结果,并没有体现出多线程并行的特性。

怎么提高并行度?答案是????拆分!

package com.leolee.multithreadProgramming.threadPool.forkJoin;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinTest
 * @Description: TODO
 * @Author LeoLee
 * @Date 2021/3/3
 * @Version V1.0
 **/
public class ForkJoinTest {

    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();//无参的构造函数默认创建的是CPU核心数大小的线程池
        System.out.println(forkJoinPool.invoke(new MyTask(1, 5)));

    }

}

/*
 * 功能描述: <br>
 * 〈特殊的任务,并非是Thread或者是Runnable〉
 *  RecursiveTask是带返回结果的任务,RecursiveAction无返回结果
 * @Param:
 * @Return: 1-n之间整数的和
 * @Author: LeoLee
 * @Date: 2021/3/3 21:28
 */
@Slf4j
class MyTask extends RecursiveTask<Integer> {

    //优化版本示例使用,高并行版本,有点类似于排序算法中的二分法
    private int begin;//开始的数字
    private int end;//结束的数字

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    public String toString() {
        return "MyTask{" +
                "begin=" + begin +
                ", end=" + end +
                '}';
    }

    @Override
    protected Integer compute() {

        //终止条件
        if (begin == end) {
            log.info("join() {}", begin);
            return begin;
        }
        if (end - begin == 1) {//这一段可写可不写,减少一次拆分而已
            log.info("join() {} + {} = {}", begin, end, begin + end);
            return begin + end;
        }

        int mid = (begin + end) / 2;

        MyTask t1 = new MyTask(begin, mid);
        t1.fork();
        MyTask t2 = new MyTask(mid + 1, end);
        t2.fork();
        log.info("fork() {} + {} = ?", t1.toString(), t2.toString());

        int result = t1.join() + t2.join();
        log.info("join() {} + {} = {}", t1, t2, result);

        return result;
    }

}
运行结果:
22:18:23.367 [ForkJoinPool-1-worker-3] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 4 + 5 = 9
22:18:23.367 [ForkJoinPool-1-worker-2] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() MyTask{begin=1, end=2} + MyTask{begin=3, end=3} = ?
22:18:23.367 [ForkJoinPool-1-worker-1] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - fork() MyTask{begin=1, end=3} + MyTask{begin=4, end=5} = ?
22:18:23.367 [ForkJoinPool-1-worker-5] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 3
22:18:23.367 [ForkJoinPool-1-worker-4] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() 1 + 2 = 3
22:18:23.390 [ForkJoinPool-1-worker-2] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() MyTask{begin=1, end=2} + MyTask{begin=3, end=3} = 6
22:18:23.390 [ForkJoinPool-1-worker-1] INFO com.leolee.multithreadProgramming.threadPool.forkJoin.MyTask - join() MyTask{begin=1, end=3} + MyTask{begin=4, end=5} = 15
15

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值