Java中的并发与多线程:高级水平
\n\nJava中的多线程是最强大同时也最复杂的主题之一。在初级阶段,我们使用synchronized和Thread,但要构建高性能、可扩展的系统,需要更深入的理解。本文将探讨高级并发机制:线程池、ForkJoinPool、使用CompletableFuture进行异步编程、锁的精细调优以及内存操作。内容面向已掌握多线程基础的开发者。
1. 线程池的高级使用:ExecutorService与配置
\n\n使用ExecutorService是工业级开发的标准做法。然而,标准的Executors.newFixedThreadPool(10)并非总是适用。我们来探讨ThreadPoolExecutor的精细配置。
import java.util.concurrent.*;\n\npublic class CustomThreadPool {\n public static void main(String[] args) {\n int corePoolSize = 4;\n int maxPoolSize = 8;\n long keepAliveTime = 30;\n TimeUnit unit = TimeUnit.SECONDS;\n BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);\n\n ThreadPoolExecutor executor = new ThreadPoolExecutor(\n corePoolSize,\n maxPoolSize,\n keepAliveTime,\n unit,\n workQueue,\n new ThreadPoolExecutor.CallerRunsPolicy() // 饱和策略\n );\n\n // 监控线程池状态\n executor.submit(() -> {\n System.out.println("活跃线程数: " + executor.getActiveCount());\n System.out.println("已完成任务数: " + executor.getCompletedTaskCount());\n });\n\n executor.shutdown();\n }\n}\n\n关键参数:
\n- \n
corePoolSize— 即使没有任务也保持的最小线程数。 \n maxPoolSize— 最大线程数。 \n keepAliveTime— 多余线程的存活时间。 \n workQueue— 任务队列。使用有界ArrayBlockingQueue可防止内存溢出。 \n - 饱和策略 — 当队列已满且所有线程都忙碌时的处理方式。
CallerRunsPolicy会减慢调用线程的速度。 \n
对于长时间I/O任务,建议增大corePoolSize;对于CPU密集型任务,应参考Runtime.getRuntime().availableProcessors()。
2. ForkJoinPool与递归任务
\n\nForkJoinPool是一个专门用于可分解为子任务(分而治之)的线程池。它高效地利用了工作窃取(work stealing)机制。
示例:递归计算数组元素之和。
\n\nimport java.util.concurrent.RecursiveTask;\nimport java.util.concurrent.ForkJoinPool;\n\npublic class SumTask extends RecursiveTask<Long> {\n private static final int THRESHOLD = 1000;\n private final int[] array;\n private final int start;\n private final int end;\n\n public SumTask(int[] array, int start, int end) {\n this.array = array;\n this.start = start;\n this.end = end;\n }\n\n @Override\n protected Long compute() {\n if (end - start <= THRESHOLD) {\n long sum = 0;\n for (int i = start; i < end; i++) {\n sum += array[i];\n }\n return sum;\n }\n int mid = (start + end) / 2;\n SumTask leftTask = new SumTask(array, start, mid);\n SumTask rightTask = new SumTask(array, mid, end);\n\n leftTask.fork(); // 异步启动\n long rightResult = rightTask.compute(); // 计算