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:最灵活的工具,支持动态参与者和多阶段协调

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

  • 设置合理的超时时间
  • 正确处理异常和中断
  • 确保资源正确释放
  • 添加监控和日志
相关推荐
小股虫2 小时前
从零开始:ActiveMQ安装、Java应用实战与Web控制台体验
java·activemq·java-activemq
java_logo2 小时前
RUSTFS Docker 容器化部署指南
java·运维·docker·容器·jenkins·运维开发
uup2 小时前
秒杀系统中的超卖与重复下单问题
java
用户8307196840822 小时前
Spring注入原型Bean,为啥”新“对象“不翼而飞”?
java
初听于你2 小时前
Thymeleaf 模板引擎讲解
java·服务器·windows·spring boot·spring·eclipse
刘 大 望2 小时前
JVM(Java虚拟机)
java·开发语言·jvm·数据结构·后端·java-ee
超级种码2 小时前
JVM 字节码指令活用手册(基于 Java 17 SE 规范)
java·jvm·python
元亓亓亓2 小时前
LeetCode热题100--155. 最小栈--中等
java·算法·leetcode
SadSunset2 小时前
(3)第一个spring程序
java·后端·spring