Java并发学习笔记20 线程池 ForkJoinPool

本文详细解析了Java并发库中的ForkJoinPool,包括其原理、构造方式及适用场景,对比了与其他线程池的区别,通过示例展示了ForkJoinTask的使用方法,并介绍了CompletionService的工作机制。
摘要由CSDN通过智能技术生成

bilibili-Java并发学习笔记20 线程池 ForkJoinPool

基于 java 1.8.0

P64_ForkJoinPool原理与构造方式详解

  1. 分而治之
  2. 工作窃取

适合 CPU 密集型计算任务,不适合 IO 密集型任务

    /**
     * @param parallelism 并行度级别 默认值 = java.lang.Runtime#availableProcessors
     * @param factory  创建新线程的工厂 默认值 = defaultForkJoinWorkerThreadFactory
     * @param handler  由于执行任务时遇到不可恢复的错误而终止的内部工作线程的处理程序 默认值为 null
     * @param asyncMode
     *      true  为从未连接的分叉任务建立本地先进先出调度模式。
                在工作线程只处理事件式异步任务的应用程序中,此模式可能比默认的基于本地堆栈的模式更合适。
     *      默认值 = false
     * @throws IllegalArgumentException 如果并行度小于或等于零,或大于实现限制
     * @throws NullPointerException if the factory is null
     * @throws SecurityException if a security manager exists and
     *         the caller is not permitted to modify threads
     *         because it does not hold {@link
     *         java.lang.RuntimePermission}{@code ("modifyThread")}
     */
    public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode) {
        this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
    }

P65_ForkJoinTask详解与示例分析

public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
    V result;
    protected abstract V compute();
}

public abstract class RecursiveAction extends ForkJoinTask<Void> {
    protected abstract void compute();
}
    /**
     * Submits a ForkJoinTask for execution.
     *
     * @param task the task to submit
     * @param <T> the type of the task's result
     * @return the task
     * @throws NullPointerException if the task is null
     * @throws RejectedExecutionException if the task cannot be
     *         scheduled for execution
     */
    public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
        if (task == null)
            throw new NullPointerException();
        externalPush(task);
        return task;
    }

ForkJoinPool 示例

package new_package.thread.p64;

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

public class ForkJoinTest {

    public static void main(String[] args) {
        //ForkJoinPool forkJoinPool = new ForkJoinPool(2);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SumTask sumTask = new SumTask(1, 100, 10);
        System.out.println(forkJoinPool.invoke(sumTask));
        forkJoinPool.shutdown();
    }
}

class SumTask extends RecursiveTask<Integer> {

    int limit;
    int start;
    int end;

    public SumTask(int start, int end, int limit) {
        this.start = start;
        this.end = end;
        this.limit = limit;
    }

    @Override
    protected Integer compute() {

        int sum = 0;
        if ((end - start) <= limit) {
            System.out.println(Thread.currentThread().getName());
            for (int i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        }

        // Fork 步骤
        int mid = (end + start) / 2;
        SumTask leftTask = new SumTask(start, mid, limit);
        SumTask rightTask = new SumTask(mid + 1, end, limit);

        // Join 步骤
        invokeAll(leftTask, rightTask);
        Integer leftResult = leftTask.join();
        Integer rightResult = rightTask.join();
        return leftResult + rightResult;
    }
}

P66_CompletionService源码详解与示例剖析

// jdk 中 CompletionService 的唯一实现
public class ExecutorCompletionService<V> implements CompletionService<V> {
    private final Executor executor;
    private final AbstractExecutorService aes;
    private final BlockingQueue<Future<V>> completionQueue;
    // ...
}

package new_package.thread.p66;

import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 * 以任务完成顺序获取到最后的结果集合
 */
public class CompletionServiceTest {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = new ThreadPoolExecutor(10,
                10,
                1,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(),
                (r, executor) -> {

                });
        CompletionService<Integer> completionService = new ExecutorCompletionService(executorService);

        IntStream.range(0, 10).forEach(r -> {
            completionService.submit(() -> {
                try {
                    Thread.sleep((long) (Math.random() * 3000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
                return r + 1;
            });
        });

        for (int i = 0; i < 10; i++) {
            System.out.println(completionService.take().get());
        }

        executorService.shutdown();
    }
}

P67_ThreadLocalRandom在多线程竞争环境下的实现策略

  1. Random
import java.util.Random;

public class RandomTest {

    public static void main(String[] args) {

        Random random = new Random();
        System.out.println(random.nextInt(10));
    }
}
  • 多线程性能问题
    • 多线程同时操作种子更新,产生竞争(自旋锁)
  • 正确性没有问题,只是在多线程高并发情况下效率低下
  1. ThreadLocalRandom
import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalRandomTest {

    public static void main(String[] args) {
        ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
        System.out.println(threadLocalRandom.nextInt(10));
    }
}
  • 解决随机数生成在多线程高并发情况下效率低的问题
  • 在并发代码中,随机数生成使用 ThreadLocalRandom 较好

  • 随机数生成器
    • 随机数生成器种子
    • 随机数生成算法
  • 对于 ThreadLocalRandom 来说,其随机器生成器的种子存放在每个的线程的 ThreadLocal 中
    • Random 是共享同一个种子

ThreadLocalRandom.java

    /**
     * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
     * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
     */
    private Object readResolve() {
        return current();
    }

    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

Thread.java

    // The following three initially uninitialized fields are exclusively
    // managed by class java.util.concurrent.ThreadLocalRandom. These
    // fields are used to build the high-performance PRNGs in the
    // concurrent code, and we can not risk accidental false sharing.
    // Hence, the fields are isolated with @Contended.

    /** The current seed for a ThreadLocalRandom */
    @sun.misc.Contended("tlr")
    long threadLocalRandomSeed;

    /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
    @sun.misc.Contended("tlr")
    int threadLocalRandomProbe;

    /** Secondary seed isolated from public ThreadLocalRandom sequence */
    @sun.misc.Contended("tlr")
    int threadLocalRandomSecondarySeed;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值