fork-join线程池

饥饿情况

  • 如果每次,对于每一个任务都分配一个pool.invoke(new Task)这种,就会由于线程的数量不够,而导致饥饿。就是所有线程都处于waiting状态。

  • 不知道为什么使用task.fork()创建新的线程,为什么不会出现饥饿的情况。
    因为正常情况下。如果线程数目太少。就没法递归到最后一个任务,从而出现前面的线程处于waiting状态。但是现在却没有新的线程处理需要计算的这个任务。导致所有的线程处于饥饿的状态。

  • 如果需要解决这种情况,应该使用三类线程,一类进行专门的任务分类,一类进行计算,最后一类进行任务的统计。估计应该是这么设计的。

  • 也可以是两类线程。一类进行分类和计算,一类进行计算。或者把统计和计算的线程做成一类。

结果比较

由于设置的thread是1e5,比较大,所以手动的时间是比parrallel的时间快上不少的。
但是实际上。如果数据的范围小于1e7,会发现,还是使用单线程的最快。
这是由于

  • 使用forkJoin会创建Task类。
  • 存在递归调用,有栈上下文的切换。
  • 会创建上下文,有线程上下文的切换。
    在这里插入图片描述

详细代码

package threadBase.threadPool;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;


class Task extends RecursiveTask <Long>{
    int l, r;
    int thread;
    public Task(int l, int r, int thread) {
        this.l = l;
        this.r = r;
        this.thread = thread;
    }
    @Override
    protected Long compute() {
        if (r - l + 1 <= thread) {
            long ans = 0;
            for (int i = l; i <= r; i++)
                ans += i;
            return ans;
        }
        int mid = l + r >> 1;
        Task t1 = new Task(l, mid, thread);
        Task t2 = new Task(mid + 1, r, thread);
        t1.fork();
        t2.fork();
        return t1.join() + t2.join();
    }
}

public class ForkjionTest {

    /*

        使用函数进行所谓的任务计算,
        不用类作为计算任务,
        直接使用lambda表达式,然后直接使用函数作为任务内容进行计算就行了。

        不是函数式接口,上面的设想不成立。服了
        但是可以写成内部函数。
        直接手动fork,手动join。
        不过这样好像就只有一个线程?
     */
    long testForkJoinInFunction(int l, int r, ForkJoinPool pool) {
        if (l == r) return l;
        int mid = l + r >> 1;
        long ans = pool.invoke(new RecursiveTask<Long>() {
            @Override
            protected Long compute() {
                long ans1 = testForkJoinInFunction(l, mid, pool); // 手动fork
                long ans2 = testForkJoinInFunction(mid + 1, r, pool);
                return ans1 + ans2; // 手动join
            }
        });
//        System.out.println("线程:" + Thread.currentThread());
        return ans;
    }

    public long testClass(int l,int r, ForkJoinPool pool) {
        Task task = new Task(l, r, (int)1e5);
        return pool.invoke(task);
    }

    public long testParralle(int l, int r) {
        long reduce = LongStream.rangeClosed(l, r).parallel().reduce(0, (x, y) -> x + y);
        return reduce;
    }
    public static void main(String[] args) {
        ForkjionTest fp = new ForkjionTest();
        ForkJoinPool pool = new ForkJoinPool(16);
        int n = (int)1e9;
        long startTime = System.currentTimeMillis();
        long ans = fp.testClass(0, n, pool);
        long endTime = System.currentTimeMillis();
        System.out.println("ans = " + ans);
        System.out.println("手动Fork-Join时间为:" + (endTime - startTime) + "ms");
        ans = 0;
        startTime = System.currentTimeMillis();
        for (int i = 0; i <= n; i++) {
            ans += i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("ans = " + ans);
        System.out.println("单线程时间为:" + (endTime - startTime) + "ms");
        startTime = System.currentTimeMillis();
        ans = fp.testParralle(0, n);
        endTime = System.currentTimeMillis();
        System.out.println("ans = " + ans);
        System.out.println("Parrallel运行时间:" + (endTime - startTime) + "ms");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值