【JUC】3、并发编程工具类

95 阅读3分钟

以下是对 Java 中 atomic 包下原子类、线程池以及线程协作工具的详细介绍,适用于并发编程场景下的知识整理。


1. java.util.concurrent.atomic 原子类

Java 提供了一系列原子操作类,位于 java.util.concurrent.atomic 包中,用于实现无锁线程安全操作。这些类基于 CAS(Compare and Swap)算法 实现。

主要类及用途:

类名用途
AtomicInteger原子整型变量
AtomicLong原子长整型变量
AtomicBoolean原子布尔值
AtomicReference<T>原子引用对象
AtomicIntegerArray原子整型数组
AtomicStampedReference带版本戳的原子引用,解决 ABA 问题
AtomicMarkableReference标记位的原子引用

示例:

AtomicInteger atomicInt = new AtomicInteger(0);
boolean success = atomicInt.compareAndSet(0, 10); // 如果当前值是0,则设为10

特点:

  • 线程安全
  • 避免使用锁
  • 适用于高并发计数器、状态标志等

2. 线程池(ThreadPool)

线程池通过复用线程减少创建销毁开销,提高系统响应速度和资源利用率。

创建方式:

Java 中通常使用 Executors 工厂类创建线程池,底层基于 ThreadPoolExecutor

常见类型:

线程池类型描述
newFixedThreadPool固定大小线程池,适合负载较重的服务器
newCachedThreadPool缓存线程池,自动回收空闲线程,适合执行短期异步任务
newSingleThreadExecutor单线程线程池,保证任务串行执行
newScheduledThreadPool支持定时和周期性任务执行

示例:

ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("Task executed"));
executor.shutdown();

核心参数说明(ThreadPoolExecutor):

参数说明
corePoolSize核心线程数
maximumPoolSize最大线程数
keepAliveTime空闲线程存活时间
unit时间单位
workQueue任务队列
threadFactory线程工厂
handler拒绝策略(如 AbortPolicy, CallerRunsPolicy 等)

3. 线程协作工具类

Java 提供了多种线程协作机制,帮助多个线程协同完成任务。

① CountDownLatch

允许一个或多个线程等待其他线程完成操作。

使用场景:

  • 多个线程并行处理任务后通知主线程继续执行

示例:

CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        try {
            Thread.sleep(1000);
        } finally {
            latch.countDown(); // 减1
        }
    }).start();
}

latch.await(); // 等待所有线程countDown完
System.out.println("All threads done");

② Semaphore

控制同时访问的线程数量,用于限流或资源池管理。

使用场景:

  • 控制数据库连接池最大连接数
  • 控制并发线程数量

示例:

Semaphore semaphore = new Semaphore(2); // 允许两个线程同时执行

semaphore.acquire(); // 获取许可
try {
    // 执行任务
} finally {
    semaphore.release(); // 释放许可
}

③ CyclicBarrier

让一组线程互相等待,直到所有线程都到达某个屏障点后再一起继续执行。

使用场景:

  • 并发测试时统一启动多个线程

示例:

CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All arrived"));

Runnable task = () -> {
    System.out.println(Thread.currentThread().getName() + " arrived");
    try {
        barrier.await(); // 等待其他线程
    } catch (Exception e) {
        e.printStackTrace();
    }
};

new Thread(task).start();
new Thread(task).start();
new Thread(task).start();

④ Exchanger

用于两个线程之间交换数据。

使用场景:

  • 生产者消费者模式中交换缓冲区

示例:

Exchanger<String> exchanger = new Exchanger<>();

new Thread(() -> {
    String data = "Data from Thread 1";
    try {
        String received = exchanger.exchange(data);
        System.out.println("Received: " + received);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

new Thread(() -> {
    String data = "Data from Thread 2";
    try {
        String received = exchanger.exchange(data);
        System.out.println("Received: " + received);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

⑤ Phaser

CyclicBarrierCountDownLatch 更灵活,支持动态注册线程、分阶段同步等。

使用场景:

  • 多阶段任务协调(如并行计算中的多轮迭代)

示例:

Phaser phaser = new Phaser();
phaser.register(); // 注册主线程

for (int i = 0; i < 3; i++) {
    phaser.register(); // 动态注册线程
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + " phase 1 done");
        phaser.arriveAndAwaitAdvance(); // 等待所有线程第一阶段完成

        System.out.println(Thread.currentThread().getName() + " phase 2 done");
        phaser.arriveAndAwaitAdvance();
    }).start();
}

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

总结对比表:

工具类作用是否可重复使用是否支持动态调整
CountDownLatch等待一组线程完成❌ 不可重复使用❌ 不支持
Semaphore控制并发数量✅ 可重复使用❌ 不支持
CyclicBarrier多线程互相等待✅ 可重复使用❌ 不支持
Exchanger两线程间交换数据✅ 可重复使用❌ 不支持
Phaser多阶段协调✅ 可重复使用✅ 支持动态注册

如果你有具体的业务场景或代码片段需要分析,我可以结合上下文进一步提供优化建议。