Java并发工具深度剖析与实战

Java并发工具深度剖析与实战

前言

Java并发编程是构建高性能应用的关键技术。Java提供了丰富的并发工具类,包括CountDownLatch、CyclicBarrier、Semaphore、Exchanger等,这些工具能够帮助我们优雅地解决多线程协作问题。本文将深入探讨这些并发工具的原理、使用场景以及在实际生产环境和开源框架中的应用。

一、CountDownLatch - 倒计时门闩

1.1 基本概念

CountDownLatch是一个同步辅助类,允许一个或多个线程等待其他线程完成操作。它通过一个计数器来实现,计数器的初始值为线程的数量,每当一个线程完成任务后计数器值减1,当计数器值为0时,等待的线程会被唤醒。

ini 复制代码
初始状态: count = 3
+--------+  +--------+  +--------+  +--------+
| 主线程 |  | 线程1  |  | 线程2  |  | 线程3  |
+--------+  +--------+  +--------+  +--------+
    |           |           |           |
    | await()   |           |           |
    | 等待...   |           |           |
    |           | countDown()           |
    |           | count=2   |           |
    |           |           | countDown()
    |           |           | count=1   |
    |           |           |           | countDown()
    |           |           |           | count=0
    | 唤醒! <---------------------------+
    | 继续执行
    v

1.2 基础使用示例

java 复制代码
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        CountDownLatch latch = new CountDownLatch(threadCount);

        System.out.println("主线程开始等待所有工作线程完成...");

        // 启动多个工作线程
        for (int i = 0; i < threadCount; i++) {
            final int taskId = i;
            new Thread(() -> {
                try {
                    System.out.println("任务" + taskId + "开始执行");
                    // 模拟耗时操作
                    Thread.sleep((long) (Math.random() * 3000));
                    System.out.println("任务" + taskId + "执行完成");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    // 计数器减1
                    latch.countDown();
                }
            }, "Worker-" + i).start();
        }

        // 等待所有线程完成
        latch.await();
        System.out.println("所有任务已完成,主线程继续执行");
    }
}

1.3 生产实战 - 批量数据初始化

java 复制代码
import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;

/**
 * 应用启动时并行加载多个数据源
 * 参考Spring Boot应用启动场景
 */
public class ApplicationStartup {

    private final ExecutorService executor =
        Executors.newFixedThreadPool(10);

    public void initialize() {
        System.out.println("应用启动中,开始初始化资源...");
        long startTime = System.currentTimeMillis();

        List<String> dataSources = List.of(
            "用户数据", "配置数据", "缓存预热",
            "数据库连接池", "消息队列"
        );

        CountDownLatch latch = new CountDownLatch(dataSources.size());

        // 并行初始化各个数据源
        for (String dataSource : dataSources) {
            executor.submit(() -> {
                try {
                    loadDataSource(dataSource);
                } finally {
                    latch.countDown();
                    System.out.println(dataSource + " 初始化完成,剩余: " +
                        latch.getCount());
                }
            });
        }

        try {
            // 等待所有数据源初始化完成,最多等待30秒
            boolean completed = latch.await(30, TimeUnit.SECONDS);

            if (completed) {
                long duration = System.currentTimeMillis() - startTime;
                System.out.println("所有资源初始化完成,耗时: " + duration + "ms");
            } else {
                System.err.println("初始化超时,部分资源未完成");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("初始化被中断");
        } finally {
            executor.shutdown();
        }
    }

    private void loadDataSource(String dataSource) {
        try {
            System.out.println("开始加载: " + dataSource);
            // 模拟加载耗时
            Thread.sleep((long) (Math.random() * 3000));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        new ApplicationStartup().initialize();
    }
}

1.4 实战案例 - 压测工具

java 复制代码
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 并发压测工具
 * 模拟JMeter、Gatling等压测工具的实现
 */
public class ConcurrentStressTester {

    private final AtomicInteger successCount = new AtomicInteger(0);
    private final AtomicInteger failCount = new AtomicInteger(0);
    private final AtomicLong totalResponseTime = new AtomicLong(0);

    /**
     * 执行压测
     * @param concurrentUsers 并发用户数
     * @param requestsPerUser 每个用户的请求数
     */
    public void runStressTest(int concurrentUsers, int requestsPerUser) {
        System.out.println("=== 压测开始 ===");
        System.out.println("并发用户数: " + concurrentUsers);
        System.out.println("每用户请求数: " + requestsPerUser);

        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(concurrentUsers);

        long testStartTime = System.currentTimeMillis();

        // 创建并发用户
        for (int i = 0; i < concurrentUsers; i++) {
            final int userId = i;
            new Thread(() -> {
                try {
                    // 等待统一开始信号
                    startLatch.await();

                    // 执行请求
                    for (int j = 0; j < requestsPerUser; j++) {
                        executeRequest(userId, j);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endLatch.countDown();
                }
            }, "User-" + i).start();
        }

        // 所有线程准备就绪,统一开始
        startLatch.countDown();

        try {
            // 等待所有请求完成
            endLatch.await();

            long testDuration = System.currentTimeMillis() - testStartTime;

            // 输出统计结果
            printStatistics(testDuration, concurrentUsers * requestsPerUser);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private void executeRequest(int userId, int requestId) {
        long startTime = System.currentTimeMillis();

        try {
            // 模拟HTTP请求
            boolean success = mockHttpRequest();

            long responseTime = System.currentTimeMillis() - startTime;
            totalResponseTime.addAndGet(responseTime);

            if (success) {
                successCount.incrementAndGet();
            } else {
                failCount.incrementAndGet();
            }

        } catch (Exception e) {
            failCount.incrementAndGet();
        }
    }

    private boolean mockHttpRequest() {
        try {
            // 模拟网络延迟 50-200ms
            Thread.sleep(50 + (long) (Math.random() * 150));
            // 90%成功率
            return Math.random() < 0.9;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    private void printStatistics(long duration, int totalRequests) {
        int success = successCount.get();
        int fail = failCount.get();
        double successRate = (double) success / totalRequests * 100;
        double avgResponseTime = (double) totalResponseTime.get() / totalRequests;
        double tps = (double) totalRequests / duration * 1000;

        System.out.println("\n=== 压测结果 ===");
        System.out.println("总耗时: " + duration + "ms");
        System.out.println("总请求数: " + totalRequests);
        System.out.println("成功数: " + success);
        System.out.println("失败数: " + fail);
        System.out.println("成功率: " + String.format("%.2f%%", successRate));
        System.out.println("平均响应时间: " + String.format("%.2fms", avgResponseTime));
        System.out.println("TPS: " + String.format("%.2f", tps));
    }

    public static void main(String[] args) {
        ConcurrentStressTester tester = new ConcurrentStressTester();
        tester.runStressTest(100, 10);
    }
}

二、CyclicBarrier - 循环栅栏

2.1 基本概念

CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。与CountDownLatch不同,CyclicBarrier可以重复使用(循环)。

csharp 复制代码
线程协作流程:
+--------+  +--------+  +--------+
| 线程1  |  | 线程2  |  | 线程3  |
+--------+  +--------+  +--------+
    |           |           |
    | await()   |           |
    | 等待...   |           |
    |           | await()   |
    |           | 等待...   |
    |           |           | await()
    | <--------屏障点到达-----+
    | 全部唤醒,继续执行
    |           |           |
    | 第二轮    |           |
    | await()   |           |
    | ...       | await()   |
    |           | ...       | await()
    | <--------再次到达屏障---+
    v           v           v

2.2 基础使用示例

java 复制代码
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {

    public static void main(String[] args) {
        int parties = 3;

        // 创建栅栏,当3个线程都到达时执行屏障动作
        CyclicBarrier barrier = new CyclicBarrier(parties, () -> {
            System.out.println("所有线程已到达屏障,执行屏障动作");
            System.out.println("========================\n");
        });

        // 启动3个线程
        for (int i = 0; i < parties; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    for (int round = 0; round < 2; round++) {
                        System.out.println("线程" + threadId + " 第" +
                            (round + 1) + "轮开始工作");

                        // 模拟工作
                        Thread.sleep((long) (Math.random() * 2000));

                        System.out.println("线程" + threadId + " 到达屏障,等待其他线程");

                        // 等待其他线程
                        barrier.await();

                        System.out.println("线程" + threadId + " 继续执行");
                    }
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, "Thread-" + i).start();
        }
    }
}

2.3 CyclicBarrier vs CountDownLatch

scss 复制代码
+-------------------+-------------------------+-------------------------+
|      特性         |    CountDownLatch       |    CyclicBarrier        |
+-------------------+-------------------------+-------------------------+
| 计数方式          | 递减到0                  | 递增到parties            |
| 是否可重用        | 不可重用                 | 可重用                   |
| 典型场景          | 等待其他线程完成         | 多线程协作分阶段执行     |
| 调用方式          | countDown() / await()   | await()                  |
| 屏障动作          | 无                       | 支持屏障到达时执行动作   |
| 异常处理          | 简单                     | 需处理BrokenBarrierException |
+-------------------+-------------------------+-------------------------+

2.4 生产实战 - 并行计算框架

java 复制代码
import java.util.concurrent.*;
import java.util.concurrent.atomic.DoubleAdder;

/**
 * 并行计算框架 - 模拟MapReduce
 * 参考Hadoop MapReduce的分治思想
 */
public class ParallelComputeFramework {

    /**
     * 并行计算大数组的总和
     */
    public static double parallelSum(double[] array, int workerCount) {
        int length = array.length;
        int chunkSize = length / workerCount;

        DoubleAdder totalSum = new DoubleAdder();
        CyclicBarrier barrier = new CyclicBarrier(workerCount, () -> {
            System.out.println("所有分片计算完成,开始汇总结果");
        });

        ExecutorService executor = Executors.newFixedThreadPool(workerCount);
        CountDownLatch latch = new CountDownLatch(workerCount);

        // Map阶段:分片计算
        for (int i = 0; i < workerCount; i++) {
            final int workerId = i;
            final int start = i * chunkSize;
            final int end = (i == workerCount - 1) ? length : (i + 1) * chunkSize;

            executor.submit(() -> {
                try {
                    // 计算当前分片
                    double partialSum = 0;
                    for (int j = start; j < end; j++) {
                        partialSum += array[j];
                    }

                    System.out.println("Worker-" + workerId + " 计算范围[" +
                        start + ", " + end + "), 部分和: " + partialSum);

                    // 等待其他Worker完成
                    barrier.await();

                    // Reduce阶段:汇总结果
                    totalSum.add(partialSum);

                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            executor.shutdown();
        }

        return totalSum.sum();
    }

    public static void main(String[] args) {
        // 创建测试数据
        int size = 10_000_000;
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = i + 1;
        }

        // 串行计算
        long start = System.currentTimeMillis();
        double sum1 = 0;
        for (double v : array) {
            sum1 += v;
        }
        long serialTime = System.currentTimeMillis() - start;
        System.out.println("串行计算结果: " + sum1 + ", 耗时: " + serialTime + "ms\n");

        // 并行计算
        start = System.currentTimeMillis();
        double sum2 = parallelSum(array, 8);
        long parallelTime = System.currentTimeMillis() - start;
        System.out.println("\n并行计算结果: " + sum2 + ", 耗时: " + parallelTime + "ms");
        System.out.println("加速比: " + String.format("%.2f",
            (double) serialTime / parallelTime));
    }
}

2.5 实战案例 - 多阶段任务协调

java 复制代码
import java.util.concurrent.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 多阶段任务协调器
 * 场景:数据ETL流程(Extract-Transform-Load)
 */
public class ETLPipeline {

    private final int workerCount = 4;
    private final List<String> extractedData = new CopyOnWriteArrayList<>();
    private final List<String> transformedData = new CopyOnWriteArrayList<>();

    public void runETL(List<String> sourceData) {
        System.out.println("开始ETL流程,数据量: " + sourceData.size());

        // 创建三阶段屏障
        CyclicBarrier extractBarrier = new CyclicBarrier(workerCount, () -> {
            System.out.println("\n=== Extract阶段完成 ===");
            System.out.println("已提取数据: " + extractedData.size() + "条\n");
        });

        CyclicBarrier transformBarrier = new CyclicBarrier(workerCount, () -> {
            System.out.println("\n=== Transform阶段完成 ===");
            System.out.println("已转换数据: " + transformedData.size() + "条\n");
        });

        CyclicBarrier loadBarrier = new CyclicBarrier(workerCount, () -> {
            System.out.println("\n=== Load阶段完成 ===");
            System.out.println("ETL流程全部完成");
        });

        ExecutorService executor = Executors.newFixedThreadPool(workerCount);
        int chunkSize = sourceData.size() / workerCount;

        for (int i = 0; i < workerCount; i++) {
            final int workerId = i;
            final int start = i * chunkSize;
            final int end = (i == workerCount - 1) ?
                sourceData.size() : (i + 1) * chunkSize;

            executor.submit(() -> {
                try {
                    // 阶段1: Extract(提取)
                    System.out.println("Worker-" + workerId + " 开始Extract");
                    List<String> chunk = extractData(sourceData, start, end);
                    extractedData.addAll(chunk);
                    extractBarrier.await();

                    // 阶段2: Transform(转换)
                    System.out.println("Worker-" + workerId + " 开始Transform");
                    List<String> transformed = transformData(chunk);
                    transformedData.addAll(transformed);
                    transformBarrier.await();

                    // 阶段3: Load(加载)
                    System.out.println("Worker-" + workerId + " 开始Load");
                    loadData(transformed);
                    loadBarrier.await();

                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }

        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private List<String> extractData(List<String> source, int start, int end) {
        List<String> result = new ArrayList<>();
        for (int i = start; i < end; i++) {
            // 模拟数据提取
            sleepRandom(10);
            result.add(source.get(i));
        }
        return result;
    }

    private List<String> transformData(List<String> data) {
        List<String> result = new ArrayList<>();
        for (String item : data) {
            // 模拟数据转换
            sleepRandom(15);
            result.add(item.toUpperCase() + "_TRANSFORMED");
        }
        return result;
    }

    private void loadData(List<String> data) {
        for (String item : data) {
            // 模拟数据加载到数据库
            sleepRandom(5);
        }
    }

    private void sleepRandom(int maxMillis) {
        try {
            Thread.sleep((long) (Math.random() * maxMillis));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        List<String> sourceData = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            sourceData.add("data_" + i);
        }

        new ETLPipeline().runETL(sourceData);
    }
}

三、Semaphore - 信号量

3.1 基本概念

Semaphore(信号量)用于控制同时访问特定资源的线程数量,它维护了一组许可证(permits),线程在访问资源前必须先获取许可证,使用完后释放许可证。

ini 复制代码
资源访问控制:

    Semaphore(3)  <- 3个许可证
         |
    +----+----+----+
    |    |    |    |
   许可1 许可2 许可3
    |    |    |
    v    v    v
+------+------+------+  等待队列: [线程4, 线程5, ...]
|线程1 |线程2 |线程3 |
+------+------+------+
   |      |      |
   v      v      v
[资源] [资源] [资源]

3.2 基础使用示例

java 复制代码
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {

    public static void main(String[] args) {
        // 创建3个许可的信号量
        Semaphore semaphore = new Semaphore(3);

        // 启动10个线程竞争资源
        for (int i = 0; i < 10; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    System.out.println("线程" + threadId + " 等待获取许可...");

                    // 获取许可
                    semaphore.acquire();

                    System.out.println("线程" + threadId + " 获得许可,开始执行");
                    System.out.println("当前可用许可数: " +
                        semaphore.availablePermits());

                    // 模拟业务处理
                    Thread.sleep(2000);

                    System.out.println("线程" + threadId + " 执行完成,释放许可");

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    // 释放许可
                    semaphore.release();
                }
            }, "Thread-" + i).start();
        }
    }
}

3.3 生产实战 - 数据库连接池

java 复制代码
import java.util.concurrent.*;
import java.util.LinkedList;

/**
 * 基于Semaphore实现的数据库连接池
 * 参考HikariCP、Druid等连接池的实现思想
 */
public class DatabaseConnectionPool {

    private final LinkedList<Connection> pool = new LinkedList<>();
    private final Semaphore semaphore;
    private final int poolSize;

    public DatabaseConnectionPool(int poolSize) {
        this.poolSize = poolSize;
        this.semaphore = new Semaphore(poolSize);

        // 初始化连接池
        for (int i = 0; i < poolSize; i++) {
            pool.add(new Connection(i));
        }
    }

    /**
     * 获取连接
     */
    public Connection getConnection(long timeout, TimeUnit unit)
            throws InterruptedException, TimeoutException {

        // 尝试获取许可
        boolean acquired = semaphore.tryAcquire(timeout, unit);

        if (!acquired) {
            throw new TimeoutException("获取连接超时");
        }

        synchronized (pool) {
            if (pool.isEmpty()) {
                // 理论上不应该发生
                semaphore.release();
                throw new IllegalStateException("连接池为空");
            }
            return pool.removeFirst();
        }
    }

    /**
     * 释放连接
     */
    public void releaseConnection(Connection connection) {
        if (connection == null) {
            return;
        }

        synchronized (pool) {
            pool.addLast(connection);
        }

        // 释放许可
        semaphore.release();
    }

    /**
     * 获取连接池统计信息
     */
    public String getStats() {
        return String.format(
            "连接池大小: %d, 可用连接: %d, 已用连接: %d",
            poolSize,
            semaphore.availablePermits(),
            poolSize - semaphore.availablePermits()
        );
    }

    /**
     * 模拟数据库连接
     */
    static class Connection {
        private final int id;

        public Connection(int id) {
            this.id = id;
        }

        public void executeQuery(String sql) {
            System.out.println("Connection-" + id + " 执行SQL: " + sql);
            // 模拟查询耗时
            try {
                Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        @Override
        public String toString() {
            return "Connection-" + id;
        }
    }

    /**
     * 测试连接池
     */
    public static void main(String[] args) {
        DatabaseConnectionPool pool = new DatabaseConnectionPool(5);
        ExecutorService executor = Executors.newFixedThreadPool(20);

        // 模拟20个并发查询
        for (int i = 0; i < 20; i++) {
            final int queryId = i;
            executor.submit(() -> {
                Connection conn = null;
                try {
                    System.out.println("查询" + queryId + " 请求连接...");
                    System.out.println(pool.getStats());

                    // 获取连接,最多等待3秒
                    conn = pool.getConnection(3, TimeUnit.SECONDS);

                    System.out.println("查询" + queryId + " 获得连接: " + conn);

                    // 执行查询
                    conn.executeQuery("SELECT * FROM users WHERE id = " + queryId);

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.err.println("查询" + queryId + " 被中断");
                } catch (TimeoutException e) {
                    System.err.println("查询" + queryId + " 获取连接超时");
                } finally {
                    // 释放连接
                    if (conn != null) {
                        pool.releaseConnection(conn);
                        System.out.println("查询" + queryId + " 释放连接: " + conn);
                    }
                }
            });
        }

        executor.shutdown();
    }
}

3.4 实战案例 - 限流器

java 复制代码
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 基于Semaphore的限流器
 * 参考Guava RateLimiter和Sentinel的实现
 */
public class RateLimiter {

    private final Semaphore semaphore;
    private final int maxPermits;
    private final long timeWindowMillis;
    private final ScheduledExecutorService scheduler;
    private final AtomicInteger rejectedCount = new AtomicInteger(0);

    /**
     * @param maxPermits 时间窗口内最大请求数
     * @param timeWindowMillis 时间窗口大小(毫秒)
     */
    public RateLimiter(int maxPermits, long timeWindowMillis) {
        this.maxPermits = maxPermits;
        this.timeWindowMillis = timeWindowMillis;
        this.semaphore = new Semaphore(maxPermits);
        this.scheduler = Executors.newScheduledThreadPool(1);

        // 定期补充许可
        startRefillTask();
    }

    /**
     * 尝试获取许可
     */
    public boolean tryAcquire() {
        boolean acquired = semaphore.tryAcquire();
        if (!acquired) {
            rejectedCount.incrementAndGet();
        }
        return acquired;
    }

    /**
     * 尝试获取许可,带超时
     */
    public boolean tryAcquire(long timeout, TimeUnit unit)
            throws InterruptedException {
        boolean acquired = semaphore.tryAcquire(timeout, unit);
        if (!acquired) {
            rejectedCount.incrementAndGet();
        }
        return acquired;
    }

    /**
     * 启动许可补充任务
     */
    private void startRefillTask() {
        scheduler.scheduleAtFixedRate(() -> {
            // 计算需要补充的许可数
            int used = maxPermits - semaphore.availablePermits();
            if (used > 0) {
                semaphore.release(used);
                System.out.println("补充许可: " + used +
                    ", 当前可用: " + semaphore.availablePermits());
            }
        }, timeWindowMillis, timeWindowMillis, TimeUnit.MILLISECONDS);
    }

    /**
     * 获取统计信息
     */
    public String getStats() {
        return String.format(
            "最大许可: %d, 可用许可: %d, 已拒绝: %d",
            maxPermits,
            semaphore.availablePermits(),
            rejectedCount.get()
        );
    }

    public void shutdown() {
        scheduler.shutdown();
    }

    /**
     * 测试限流器
     */
    public static void main(String[] args) throws InterruptedException {
        // 创建限流器:每秒最多10个请求
        RateLimiter limiter = new RateLimiter(10, 1000);

        ExecutorService executor = Executors.newFixedThreadPool(20);

        System.out.println("开始压测,尝试每秒发送50个请求...\n");

        // 模拟高并发请求
        for (int i = 0; i < 100; i++) {
            final int requestId = i;

            executor.submit(() -> {
                if (limiter.tryAcquire()) {
                    System.out.println("请求" + requestId + " 通过限流");
                    // 模拟业务处理
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                } else {
                    System.err.println("请求" + requestId + " 被限流");
                }
            });

            // 控制发送速率
            if (i % 10 == 9) {
                Thread.sleep(200);
            }
        }

        Thread.sleep(3000);
        System.out.println("\n" + limiter.getStats());

        executor.shutdown();
        limiter.shutdown();
    }
}

四、Exchanger - 数据交换器

4.1 基本概念

Exchanger用于两个线程之间交换数据,它提供了一个同步点,两个线程可以在这个点上交换彼此的数据。

diff 复制代码
数据交换流程:
+----------+                    +----------+
| 线程A    |                    | 线程B    |
+----------+                    +----------+
    |                                |
    | 持有数据: DataA                |
    |                                | 持有数据: DataB
    v                                v
+------------------------------------------+
|        exchange() 同步点                 |
+------------------------------------------+
    |                                |
    | 获得: DataB                    | 获得: DataA
    v                                v

4.2 基础使用示例

java 复制代码
import java.util.concurrent.Exchanger;

public class ExchangerDemo {

    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();

        // 线程A
        new Thread(() -> {
            try {
                String data = "来自线程A的数据";
                System.out.println("线程A准备交换数据: " + data);

                // 交换数据
                String received = exchanger.exchange(data);

                System.out.println("线程A收到数据: " + received);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Thread-A").start();

        // 线程B
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 延迟1秒

                String data = "来自线程B的数据";
                System.out.println("线程B准备交换数据: " + data);

                // 交换数据
                String received = exchanger.exchange(data);

                System.out.println("线程B收到数据: " + received);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Thread-B").start();
    }
}

4.3 生产实战 - 双缓冲技术

java 复制代码
import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;

/**
 * 双缓冲技术实现
 * 一个线程负责生成数据,另一个线程负责处理数据
 * 使用Exchanger实现零拷贝的缓冲区交换
 */
public class DoubleBuffering {

    private final Exchanger<List<String>> exchanger = new Exchanger<>();
    private volatile boolean running = true;

    /**
     * 生产者线程:生成数据
     */
    class Producer implements Runnable {
        @Override
        public void run() {
            List<String> currentBuffer = new ArrayList<>();
            int batchSize = 10;
            int count = 0;

            try {
                while (running) {
                    // 生成数据
                    for (int i = 0; i < batchSize; i++) {
                        String data = "Data-" + (count++);
                        currentBuffer.add(data);
                        Thread.sleep(50); // 模拟数据生成耗时
                    }

                    System.out.println("生产者: 生成了" + currentBuffer.size() +
                        "条数据,准备交换缓冲区");

                    // 交换缓冲区
                    currentBuffer = exchanger.exchange(currentBuffer);

                    System.out.println("生产者: 获得空缓冲区,继续生产");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 消费者线程:处理数据
     */
    class Consumer implements Runnable {
        @Override
        public void run() {
            List<String> currentBuffer = new ArrayList<>();

            try {
                while (running) {
                    // 交换缓冲区
                    currentBuffer = exchanger.exchange(currentBuffer);

                    System.out.println("消费者: 获得" + currentBuffer.size() +
                        "条数据,开始处理");

                    // 处理数据
                    for (String data : currentBuffer) {
                        processData(data);
                    }

                    System.out.println("消费者: 处理完成,清空缓冲区");
                    currentBuffer.clear();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        private void processData(String data) {
            // 模拟数据处理
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void start() throws InterruptedException {
        Thread producer = new Thread(new Producer(), "Producer");
        Thread consumer = new Thread(new Consumer(), "Consumer");

        producer.start();
        consumer.start();

        // 运行10秒后停止
        Thread.sleep(10000);
        running = false;

        producer.join();
        consumer.join();
    }

    public static void main(String[] args) throws InterruptedException {
        new DoubleBuffering().start();
    }
}

4.4 实战案例 - 遗传算法

java 复制代码
import java.util.concurrent.*;
import java.util.*;

/**
 * 遗传算法实现 - 使用Exchanger进行种群交换
 * 模拟并行遗传算法求解优化问题
 */
public class GeneticAlgorithm {

    private final Exchanger<Population> exchanger = new Exchanger<>();
    private static final int POPULATION_SIZE = 100;
    private static final int GENERATIONS = 50;

    /**
     * 种群
     */
    static class Population {
        List<Individual> individuals = new ArrayList<>();

        public Individual getBest() {
            return individuals.stream()
                .max(Comparator.comparingDouble(Individual::getFitness))
                .orElse(null);
        }

        public void addIndividual(Individual individual) {
            individuals.add(individual);
        }

        public int size() {
            return individuals.size();
        }
    }

    /**
     * 个体
     */
    static class Individual {
        double[] genes;
        double fitness;

        public Individual(int geneSize) {
            genes = new double[geneSize];
            Random random = new Random();
            for (int i = 0; i < geneSize; i++) {
                genes[i] = random.nextDouble() * 100;
            }
            calculateFitness();
        }

        private void calculateFitness() {
            // 适应度函数:求基因值之和的平方根
            double sum = 0;
            for (double gene : genes) {
                sum += gene;
            }
            fitness = Math.sqrt(sum);
        }

        public double getFitness() {
            return fitness;
        }
    }

    /**
     * 进化岛(子种群)
     */
    class EvolutionIsland implements Callable<Individual> {
        private final int islandId;
        private Population population;

        public EvolutionIsland(int islandId) {
            this.islandId = islandId;
            this.population = initializePopulation();
        }

        private Population initializePopulation() {
            Population pop = new Population();
            for (int i = 0; i < POPULATION_SIZE / 2; i++) {
                pop.addIndividual(new Individual(10));
            }
            return pop;
        }

        @Override
        public Individual call() throws Exception {
            for (int gen = 0; gen < GENERATIONS; gen++) {
                // 进化
                evolve();

                // 每隔5代交换一次种群
                if (gen % 5 == 0 && gen > 0) {
                    System.out.println("岛屿" + islandId + " 第" + gen +
                        "代,准备交换种群");

                    // 交换部分个体
                    population = exchanger.exchange(population,
                        1, TimeUnit.SECONDS);

                    System.out.println("岛屿" + islandId + " 完成种群交换");
                }

                // 输出当前最优解
                if (gen % 10 == 0) {
                    Individual best = population.getBest();
                    System.out.println("岛屿" + islandId + " 第" + gen +
                        "代最优适应度: " +
                        String.format("%.2f", best.getFitness()));
                }
            }

            return population.getBest();
        }

        private void evolve() {
            // 选择、交叉、变异(简化实现)
            Random random = new Random();
            Population newPop = new Population();

            while (newPop.size() < POPULATION_SIZE / 2) {
                // 选择两个父代
                Individual parent1 = population.individuals
                    .get(random.nextInt(population.size()));
                Individual parent2 = population.individuals
                    .get(random.nextInt(population.size()));

                // 生成子代(简化:直接选择适应度较高的)
                Individual child = parent1.getFitness() > parent2.getFitness()
                    ? parent1 : parent2;

                newPop.addIndividual(child);
            }

            population = newPop;
        }
    }

    /**
     * 运行并行遗传算法
     */
    public void run() throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 创建两个进化岛
        EvolutionIsland island1 = new EvolutionIsland(1);
        EvolutionIsland island2 = new EvolutionIsland(2);

        // 并行进化
        Future<Individual> future1 = executor.submit(island1);
        Future<Individual> future2 = executor.submit(island2);

        // 获取结果
        Individual best1 = future1.get();
        Individual best2 = future2.get();

        System.out.println("\n=== 最终结果 ===");
        System.out.println("岛屿1最优适应度: " +
            String.format("%.2f", best1.getFitness()));
        System.out.println("岛屿2最优适应度: " +
            String.format("%.2f", best2.getFitness()));

        Individual globalBest = best1.getFitness() > best2.getFitness()
            ? best1 : best2;
        System.out.println("全局最优适应度: " +
            String.format("%.2f", globalBest.getFitness()));

        executor.shutdown();
    }

    public static void main(String[] args) throws Exception {
        new GeneticAlgorithm().run();
    }
}

五、Phaser - 阶段器

5.1 基本概念

Phaser是JDK 7引入的同步工具,它比CyclicBarrier更加灵活,支持动态调整参与者数量,并且可以控制多个阶段的执行。

lua 复制代码
Phaser工作流程:

        Phase 0          Phase 1          Phase 2
          |                |                |
    +-----+-----+    +-----+-----+    +-----+-----+
    |     |     |    |     |     |    |     |     |
  线程1 线程2 线程3  线程1 线程2 线程3  线程1 线程2 线程3
    |     |     |    |     |     |    |     |     |
    +-----+-----+    +-----+-----+    +-----+-----+
          |                |                |
       arriveAndAwaitAdvance()

5.2 基础使用示例

java 复制代码
import java.util.concurrent.Phaser;

public class PhaserDemo {

    public static void main(String[] args) {
        // 创建Phaser,3个参与者
        Phaser phaser = new Phaser(3) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("==== 阶段" + phase + "完成 ====\n");
                // 返回true表示终止,false表示继续
                return phase >= 2; // 执行3个阶段后终止
            }
        };

        // 启动3个线程
        for (int i = 0; i < 3; i++) {
            final int threadId = i;
            new Thread(() -> {
                for (int phase = 0; phase < 3; phase++) {
                    System.out.println("线程" + threadId + " 阶段" + phase + "开始");

                    // 模拟工作
                    try {
                        Thread.sleep((long) (Math.random() * 2000));
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }

                    System.out.println("线程" + threadId + " 阶段" + phase + "完成");

                    // 等待其他线程完成当前阶段
                    phaser.arriveAndAwaitAdvance();
                }
            }, "Thread-" + i).start();
        }
    }
}

5.3 生产实战 - 批处理任务

java 复制代码
import java.util.concurrent.*;
import java.util.*;

/**
 * 分阶段批处理任务
 * 场景:大数据处理流水线
 */
public class BatchProcessingPipeline {

    /**
     * 数据处理任务
     */
    static class DataProcessor implements Runnable {
        private final Phaser phaser;
        private final int processorId;
        private final List<String> data;

        public DataProcessor(Phaser phaser, int processorId, List<String> data) {
            this.phaser = phaser;
            this.processorId = processorId;
            this.data = data;
            phaser.register(); // 注册到phaser
        }

        @Override
        public void run() {
            try {
                // 阶段1:数据验证
                validateData();
                phaser.arriveAndAwaitAdvance();

                // 阶段2:数据清洗
                cleanData();
                phaser.arriveAndAwaitAdvance();

                // 阶段3:数据转换
                transformData();
                phaser.arriveAndAwaitAdvance();

                // 阶段4:数据保存
                saveData();
                phaser.arriveAndAwaitAdvance();

            } finally {
                phaser.arriveAndDeregister(); // 注销
            }
        }

        private void validateData() {
            System.out.println("处理器" + processorId + " 验证数据: " + data.size() + "条");
            sleep(500);
        }

        private void cleanData() {
            System.out.println("处理器" + processorId + " 清洗数据");
            sleep(800);
        }

        private void transformData() {
            System.out.println("处理器" + processorId + " 转换数据");
            sleep(1000);
        }

        private void saveData() {
            System.out.println("处理器" + processorId + " 保存数据");
            sleep(600);
        }

        private void sleep(long millis) {
            try {
                Thread.sleep(millis);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        // 创建Phaser
        Phaser phaser = new Phaser(1) { // 主线程也参与
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                String[] phases = {"验证", "清洗", "转换", "保存"};
                System.out.println("\n==== " + phases[phase] + "阶段完成 ====\n");
                return phase >= 3; // 4个阶段后终止
            }
        };

        // 准备测试数据
        List<List<String>> batches = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            List<String> batch = new ArrayList<>();
            for (int j = 0; j < 100; j++) {
                batch.add("data_" + (i * 100 + j));
            }
            batches.add(batch);
        }

        // 创建处理器
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < batches.size(); i++) {
            executor.submit(new DataProcessor(phaser, i, batches.get(i)));
        }

        // 主线程参与协调
        for (int phase = 0; phase < 4; phase++) {
            phaser.arriveAndAwaitAdvance();
        }

        phaser.arriveAndDeregister(); // 主线程注销

        executor.shutdown();
        System.out.println("\n所有批次处理完成");
    }
}

六、并发工具综合对比

6.1 功能对比表

diff 复制代码
+------------------+------------------+------------------+------------------+
|      工具        |    使用场景      |      特点        |    复杂度        |
+------------------+------------------+------------------+------------------+
| CountDownLatch   | 等待多个线程完成 | 一次性,不可重用  | 简单             |
|                  | 主线程等待子线程 | 计数递减到0      |                  |
+------------------+------------------+------------------+------------------+
| CyclicBarrier    | 多线程协作       | 可循环使用       | 中等             |
|                  | 分阶段执行       | 支持屏障动作     |                  |
+------------------+------------------+------------------+------------------+
| Semaphore        | 资源访问控制     | 限制并发数       | 简单             |
|                  | 限流             | 可获取多个许可   |                  |
+------------------+------------------+------------------+------------------+
| Exchanger        | 线程间数据交换   | 仅支持两个线程   | 简单             |
|                  | 双缓冲           | 同步交换数据     |                  |
+------------------+------------------+------------------+------------------+
| Phaser           | 动态多阶段协作   | 最灵活           | 复杂             |
|                  | 可动态注册/注销  | 支持分层         |                  |
+------------------+------------------+------------------+------------------+

6.2 选型建议

java 复制代码
/**
 * 并发工具选型指南
 */
public class ConcurrencyToolSelection {

    /**
     * 场景1: 等待所有子任务完成 -> CountDownLatch
     */
    public void scenario1() {
        // 主线程启动多个子线程,等待所有子线程完成后继续
        // 示例:应用启动时加载多个资源
    }

    /**
     * 场景2: 多线程循环协作 -> CyclicBarrier
     */
    public void scenario2() {
        // 多个线程需要在多个阶段进行同步
        // 示例:并行计算,每轮计算后同步结果
    }

    /**
     * 场景3: 限制资源访问数量 -> Semaphore
     */
    public void scenario3() {
        // 限制同时访问某资源的线程数
        // 示例:数据库连接池、限流器
    }

    /**
     * 场景4: 两线程交换数据 -> Exchanger
     */
    public void scenario4() {
        // 两个线程需要在某个点交换数据
        // 示例:生产者-消费者模式、双缓冲技术
    }

    /**
     * 场景5: 复杂多阶段协调 -> Phaser
     */
    public void scenario5() {
        // 多个线程需要经过多个阶段,且参与者数量可能动态变化
        // 示例:批处理流水线、并行迭代算法
    }
}

七、在开源框架中的应用

7.1 Spring Cloud Gateway限流

java 复制代码
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import java.util.concurrent.Semaphore;

/**
 * 模拟Spring Cloud Gateway的限流实现
 */
public class GatewayRateLimiter {

    private final Semaphore semaphore;

    public GatewayRateLimiter(int capacity) {
        this.semaphore = new Semaphore(capacity);
    }

    public boolean allowRequest() {
        return semaphore.tryAcquire();
    }

    public void releaseRequest() {
        semaphore.release();
    }

    /**
     * 处理请求
     */
    public String handleRequest(String requestId) {
        if (allowRequest()) {
            try {
                System.out.println("请求" + requestId + "通过网关");
                // 处理业务逻辑
                Thread.sleep(100);
                return "Success";
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return "Interrupted";
            } finally {
                releaseRequest();
            }
        } else {
            System.err.println("请求" + requestId + "被限流");
            return "RateLimited";
        }
    }
}

7.2 Dubbo服务启动

java 复制代码
/**
 * 模拟Dubbo服务启动过程中使用CountDownLatch
 */
public class DubboServiceBootstrap {

    public void start() {
        System.out.println("Dubbo服务启动中...");

        int serviceCount = 5;
        CountDownLatch latch = new CountDownLatch(serviceCount);

        // 并行导出多个服务
        String[] services = {
            "UserService", "OrderService", "ProductService",
            "PaymentService", "NotificationService"
        };

        ExecutorService executor = Executors.newFixedThreadPool(serviceCount);

        for (String service : services) {
            executor.submit(() -> {
                try {
                    exportService(service);
                } finally {
                    latch.countDown();
                }
            });
        }

        try {
            latch.await(30, TimeUnit.SECONDS);
            System.out.println("所有服务导出完成");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("服务启动被中断");
        } finally {
            executor.shutdown();
        }
    }

    private void exportService(String serviceName) {
        System.out.println("导出服务: " + serviceName);
        try {
            Thread.sleep((long) (Math.random() * 2000));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(serviceName + " 导出完成");
    }
}

八、最佳实践与注意事项

8.1 常见陷阱

java 复制代码
public class CommonPitfalls {

    /**
     * 陷阱1: CountDownLatch计数错误导致永久等待
     */
    public void pitfall1() {
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 2; i++) { // 只启动2个线程,但计数是3
            new Thread(() -> {
                latch.countDown();
            }).start();
        }

        try {
            latch.await(); // 永远等待!
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 解决方案:使用超时版本的await
     */
    public void pitfall1Solution() {
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                latch.countDown();
            }).start();
        }

        try {
            boolean completed = latch.await(5, TimeUnit.SECONDS);
            if (!completed) {
                System.err.println("等待超时,某些任务未完成");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 陷阱2: Semaphore未正确释放导致资源泄漏
     */
    public void pitfall2() {
        Semaphore semaphore = new Semaphore(5);

        try {
            semaphore.acquire();
            // 业务代码
            if (Math.random() > 0.5) {
                throw new RuntimeException("业务异常");
            }
            semaphore.release(); // 异常时无法执行!
        } catch (Exception e) {
            // 资源泄漏
        }
    }

    /**
     * 解决方案:在finally中释放
     */
    public void pitfall2Solution() {
        Semaphore semaphore = new Semaphore(5);

        try {
            semaphore.acquire();
            // 业务代码
            if (Math.random() > 0.5) {
                throw new RuntimeException("业务异常");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 确保释放
        }
    }

    /**
     * 陷阱3: CyclicBarrier屏障破损
     */
    public void pitfall3() {
        CyclicBarrier barrier = new CyclicBarrier(3);

        for (int i = 0; i < 3; i++) {
            final int id = i;
            new Thread(() -> {
                try {
                    if (id == 1) {
                        throw new RuntimeException("线程1异常");
                    }
                    barrier.await(); // 其他线程会抛出BrokenBarrierException
                } catch (Exception e) {
                    System.err.println("线程" + id + "异常: " + e.getMessage());
                }
            }).start();
        }
    }

    /**
     * 解决方案:捕获BrokenBarrierException并重置
     */
    public void pitfall3Solution() {
        CyclicBarrier barrier = new CyclicBarrier(3);

        for (int i = 0; i < 3; i++) {
            final int id = i;
            new Thread(() -> {
                try {
                    barrier.await();
                } catch (BrokenBarrierException e) {
                    System.err.println("屏障已破损,重置");
                    barrier.reset();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
    }
}

8.2 性能优化建议

sql 复制代码
+------------------------------------------------------------------+
|                     并发工具使用建议                               |
+------------------------------------------------------------------+
| 1. 合理选择工具                                                    |
|    - 根据实际场景选择最合适的工具                                   |
|    - 避免过度设计,简单场景用简单工具                               |
+------------------------------------------------------------------+
| 2. 设置超时时间                                                    |
|    - await/acquire操作使用带超时的版本                             |
|    - 避免无限等待导致系统hang住                                    |
+------------------------------------------------------------------+
| 3. 正确处理中断                                                    |
|    - 捕获InterruptedException后恢复中断状态                        |
|    - 不要吞掉中断异常                                              |
+------------------------------------------------------------------+
| 4. 资源释放                                                        |
|    - 在finally块中释放资源                                         |
|    - 使用try-with-resources(如果支持)                           |
+------------------------------------------------------------------+
| 5. 监控与日志                                                      |
|    - 记录关键节点的日志                                            |
|    - 监控等待时间、成功率等指标                                     |
+------------------------------------------------------------------+

总结

Java并发工具为我们提供了强大的多线程协作能力:

  1. CountDownLatch:适用于等待多个线程完成任务的场景,如应用启动、批量任务等
  2. CyclicBarrier:适用于多线程分阶段协作,可循环使用
  3. Semaphore:适用于控制资源访问数量,如连接池、限流器
  4. Exchanger:适用于两线程间数据交换,如双缓冲、遗传算法
  5. Phaser:最灵活的工具,支持动态参与者和多阶段协调

在实际应用中,需要根据具体场景选择合适的工具,并注意:

  • 设置合理的超时时间
  • 正确处理异常和中断
  • 确保资源正确释放
  • 添加监控和日志
相关推荐
言慢行善5 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星5 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟5 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z5 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可5 小时前
Java 中的实现类是什么
java·开发语言
He少年5 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
克里斯蒂亚诺更新6 小时前
myeclipse的pojie
java·ide·myeclipse
迷藏4946 小时前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4946 小时前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链
qq_433502186 小时前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书