Java并发工具常用类

7 阅读9分钟

1、线程池

1.1 ThreadPoolExecutor

(1)构造方法与核心参数 ThreadPoolExecutor 的构造函数包含 7 个关键参数,开发者可以根据实际需求进行精细化配置:

  • ‌corePoolSize‌:核心线程数。即使线程空闲,核心线程也会保持存活,除非设置 allowCoreThreadTimeOut。
  • ‌maximumPoolSize‌:最大线程数。当任务队列满且当前线程数小于最大线程数时,会创建新线程处理任务。
  • ‌keepAliveTime‌:非核心线程的空闲存活时间。当线程数超过核心线程数后,若空闲时间超过该值,线程将被回收。
  • ‌unit‌:keepAliveTime 的时间单位,如 TimeUnit.SECONDS。
  • ‌workQueue‌:任务队列,用于存放等待执行的任务。常见的类型包括:
    • SynchronousQueue:无缓冲队列,任务必须被立即处理。
    • LinkedBlockingQueue:无界队列,任务可无限排队。
    • ArrayBlockingQueue:有界队列,任务数量受限。
  • ‌threadFactory‌:用于创建新线程时调用的工厂类,可用于设置线程名等。
  • ‌rejectedExecutionHandler‌:拒绝策略,当任务无法被处理时的处理方式。常见策略包括:
    • AbortPolicy:抛出异常。
    • CallerRunsPolicy:由调用线程执行任务。
    • DiscardPolicy:直接丢弃任务。
    • DiscardOldestPolicy:丢弃队列中最旧的任务并重试。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
  2, // corePoolSize 核心线程数
  10, // maximumPoolSize 最大线程数。当任务队列满且当前线程数小于最大线程数时,会创建新线程处理任务
  10L, // keepAliveTime 非核心线程的空闲存活时间。当线程数超过核心线程数后,若空闲时间超过该值,线程将被回收
  TimeUnit.SECONDS, // keepAliveTime 的时间单位
  new LinkedBlockingQueue<>(100) // 任务队列,用于存放等待执行的任务
);

2、显式锁(Lock 体系)

作用:比 synchronized 更灵活,支持可中断、超时、公平锁、多个条件队列。

2.1. Lock 接口

核心方法:lock()、unlock()、tryLock()、lockInterruptibly()

  • lock():死等锁,拿不到就一直阻塞,不响应中断
  • lockInterruptibly():可中断地等锁,阻塞时能响应中断并抛异常
  • tryLock():立马尝试,拿到返回 true,拿不到直接返回 false,不阻塞
  • tryLock(long, TimeUnit):限时等待,超时还拿不到就放弃,也可被中断
import java.util.concurrent.locks.ReentrantLock;

public class TestCurrent {

    private final ReentrantLock lock = new ReentrantLock();
    public void performTask() {
        try {
            System.out.println(Thread.currentThread().getName() + " 尝试获取锁...");
            lock.lockInterruptibly();
            try {
                System.out.println(Thread.currentThread().getName() + " 已获得锁.");
                // 模拟执行一些耗时操作
                Thread.sleep(5000);
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + " 已释放锁.");
            }

        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(Thread.currentThread().getName() + "被中断了,未能获取到锁.");
        }
    }

    public static void main(String[] args) throws Exception{
        TestCurrent example = new TestCurrent();
        Thread thread1 = new Thread(example::performTask, "Thread-1");
        Thread thread2 = new Thread(example::performTask, "Thread-2");
        thread1.start();
        Thread.sleep(100); // 让thread1先拿到锁
        thread2.start();
        Thread.sleep(100); // 等待thread2进入阻塞状态
        thread2.interrupt(); // 发出中断信号
    }
}

2.2. ReentrantLock

可重入锁(最常用),支持公平 / 非公平锁 用法:手动加锁、手动释放(必须在 finally 里释放)

2.3. ReentrantReadWriteLock

读写锁:读锁共享、写锁独占 适合读多写少场景,大幅提升并发读性能

  • readLock():共享锁
  • writeLock():独占锁

2.4. StampedLock

JDK8 新增,比读写锁更快,支持乐观读

  • readLock():乐观读锁机制
  • writeLock():独占写锁机制
  • asReadLock()
  • asWriteLock()

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;

public class StampedLockExample {
    private final StampedLock stampedLock = new StampedLock();
    private int value = 0;

    // 使用 readLock 进行读操作
    public void readWithReadLock() {
        long stamp = stampedLock.readLock();
        try {
            System.out.println("Read with readLock: " + value);
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    // 使用 writeLock 进行写操作
    public void writeWithWriteLock() {
        long stamp = stampedLock.writeLock();
        try {
            value++;
            System.out.println("Write with writeLock: " + value);
        } finally {
            stampedLock.unlockWrite(stamp);
        }
    }

    // 使用 asReadLock 获取普通 ReadLock 并进行读操作
    public void readWithAsReadLock() {
        Lock readLock = stampedLock.asReadLock();
        readLock.lock();
        try {
            System.out.println("Read with asReadLock: " + value);
        } finally {
            readLock.unlock();
        }
    }

    // 使用 asWriteLock 获取普通 WriteLock 并进行写操作
    public void writeWithAsWriteLock() {
        Lock writeLock = stampedLock.asWriteLock();
        writeLock.lock();
        try {
            value++;
            System.out.println("Write with asWriteLock: " + value);
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        StampedLockExample example = new StampedLockExample();

        Thread reader1 = new Thread(example::readWithReadLock);
        Thread writer1 = new Thread(example::writeWithWriteLock);
        Thread reader2 = new Thread(example::readWithAsReadLock);
        Thread writer2 = new Thread(example::writeWithAsWriteLock);

        reader1.start();
        writer1.start();
        reader2.start();
        writer2.start();

        reader1.join();
        writer1.join();
        reader2.join();
        writer2.join();
    }
}

3、线程同步器(协调多线程执行顺序)

作用:解决线程等待、计数、栅栏、交换等协作问题。

3.1. CountDownLatch

倒计时门闩:一个线程等待N 个线程执行完毕再执行 场景:主线程等待所有子线程加载完数据再汇总

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {

    public static void main(String[] args) throws InterruptedException {
        // 创建一个计数为3的CountDownLatch
        CountDownLatch latch = new CountDownLatch(3);

        // 启动三个工作线程
        Thread worker1 = new Thread(new Worker(latch, "Worker-1"));
        Thread worker2 = new Thread(new Worker(latch, "Worker-2"));
        Thread worker3 = new Thread(new Worker(latch, "Worker-3"));

        worker1.start();
        worker2.start();
        worker3.start();

        // 主线程等待所有工作线程完成
        System.out.println("主线程等待所有子线程完成...");
        latch.await(); // 阻塞直到计数归零
        System.out.println("所有子线程已完成,主线程继续执行。");
    }

    static class Worker implements Runnable {
        private final CountDownLatch latch;
        private final String name;

        public Worker(CountDownLatch latch, String name) {
            this.latch = latch;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println(name + " 正在执行任务...");
                Thread.sleep((long) (Math.random() * 5000)); // 模拟耗时操作
                System.out.println(name + " 完成任务!");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                latch.countDown(); // 计数减一
            }
        }
    }
}

3.2. CyclicBarrier

循环栅栏:N 个线程互相等待,都到达后一起执行 场景:多线程分批计算,全部就绪后统一汇总 支持重复使用(区别于 CountDownLatch)

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {

    public static void main(String[] args) {
        int numberOfThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
            System.out.println("所有线程都已到达屏障点,继续执行后续任务...");
        });

        for (int i = 1; i <= numberOfThreads; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    System.out.println("线程 " + threadId + " 正在执行任务...");
                    Thread.sleep((long) (Math.random() * 1000)); // 模拟任务耗时
                    System.out.println("线程 " + threadId + " 完成任务,等待其他线程...");

                    // 到达屏障点并等待其他线程
                    barrier.await();

                    System.out.println("线程 " + threadId + " 继续执行后续工作...");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

3.3. Semaphore

信号量:控制同时执行的线程数量 场景:接口限流、数据库连接池、资源池控制并发数

import java.util.concurrent.Semaphore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.Random;

public class SemaphoreExample {
    // 创建一个Semaphore实例,允许最多3个线程同时访问资源
    private static final Semaphore semaphore = new Semaphore(3);
    private static final Random random = new Random();
    
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(10);
        
        System.out.println("开始执行任务,最多允许3个线程同时访问资源...");
        
        // 提交10个任务
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    // 获取许可
                    System.out.println("任务 " + taskId + " 尝试获取许可...");
                    semaphore.acquire();
                    
                    System.out.println("任务 " + taskId + " 获取到许可,开始执行任务...");
                    // 模拟任务执行时间
                    Thread.sleep(random.nextInt(3000) + 1000);
                    System.out.println("任务 " + taskId + " 执行完成,释放许可。");
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.err.println("任务 " + taskId + " 被中断");
                } finally {
                    // 释放许可
                    semaphore.release();
                }
            });
        }
        
        // 关闭线程池
        executor.shutdown();
        try {
            // 等待所有任务完成
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        
        System.out.println("所有任务执行完毕。");
    }
}

3.4. Exchanger

线程间数据交换器:两个线程交换数据 场景:线程间数据传输、校对数据

import java.util.concurrent.Exchanger;

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

        // 线程A
        Thread threadA = new Thread(() -> {
            try {
                System.out.println("线程A:准备交换数据...");
                String dataA = "来自线程A的数据";
                String receivedData = exchanger.exchange(dataA);
                System.out.println("线程A:接收到 " + receivedData);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("线程A被中断");
            }
        });

        // 线程B
        Thread threadB = new Thread(() -> {
            try {
                System.out.println("线程B:准备交换数据...");
                String dataB = "来自线程B的数据";
                String receivedData = exchanger.exchange(dataB);
                System.out.println("线程B:接收到 " + receivedData);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("线程B被中断");
            }
        });

        threadA.start();
        threadB.start();

        try {
            threadA.join();
            threadB.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("主线程被中断");
        }

        System.out.println("程序结束");
    }
}

4、并发集合(线程安全的集合)

作用:替代线程不安全的 ArrayList、HashMap,比 Vector、Hashtable 性能高。

4.1. CopyOnWriteArrayList

线程安全的 ArrayList 读无锁、写加锁复制数组 场景:读多写少的列表(白名单、配置列表)

4.2. CopyOnWriteArraySet

线程安全的 Set,底层基于 CopyOnWriteArrayList

4.3. ConcurrentHashMap

最常用并发 Map,线程安全、高性能 JDK7:分段锁 JDK8:CAS + synchronized 替代 HashMap、Hashtable

4.4. ConcurrentSkipListMap / ConcurrentSkipListSet

有序并发集合,高并发下排序性能好 场景:高并发、需要排序的场景

4.5. ConcurrentLinkedQueue

无锁、高性能并发队列 场景:高并发任务队列

4.6. 阻塞队列(BlockingQueue)

线程安全的队列,生产者 - 消费者模式核心

  • ArrayBlockingQueue:有界数组队列
  • LinkedBlockingQueue:无界 / 有界链表队列
  • PriorityBlockingQueue:优先级队列
  • SynchronousQueue:不存储元素的队列(直接传递)
  • DelayQueue:延迟队列(定时任务、超时订单)

5、原子类(无锁线程安全)

基于 CAS 无锁算法,性能远超 synchronized,适合简单计数、状态更新。

5.1基本类型

  • AtomicInteger:原子整数
  • AtomicLong:原子长整数
  • AtomicBoolean:原子布尔

5.2引用类型

  • AtomicReference:原子引用对象

5.3数组类型

  • AtomicIntegerArray
  • AtomicLongArray

5.4原子更新字段

  • AtomicIntegerFieldUpdater:用于对某个类的 int 类型字段进行原子性更新操作
  • AtomicLongFieldUpdater

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class AtomicIntegerFieldUpdaterExample {
    static class Counter {
        volatile int count; // 被更新的字段必须是 volatile 修饰的非 static 字段
        int age;

        public Counter(int count) {
            this.count = count;
        }

        public int getCount() {
            return count;
        }
    }

    // 创建 AtomicIntegerFieldUpdater 实例
    private static final AtomicIntegerFieldUpdater<Counter> updater =
            AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");

    public static void main(String[] args) {
        Counter counter = new Counter(0);

        // 原子性增加并获取值
        int newValue = updater.incrementAndGet(counter);
        System.out.println("Increased count: " + newValue); // 输出: Increased count: 1

        // 原子性比较并设置值 (期望当前值为1,更新为5)
        boolean updated = updater.compareAndSet(counter, 1, 5);
        System.out.println("Compare and set success: " + updated); // 输出: Compare and set success: true
        System.out.println("New count value: " + counter.getCount()); // 输出: New count value: 5
    }
}

5.5JDK8 增强(高并发下性能更高)

  • LongAdder 替代 AtomicLong
  • DoubleAdder
  • LongAccumulator
  • DoubleAccumulator

6、线程管理工具

6.1. ThreadLocal

线程本地变量,每个线程独立副本,线程安全 场景:存储用户会话、数据库连接、请求上下文


public class ThreadLocalExample {

    // 创建一个ThreadLocal变量,用于存储每个线程独立的Integer值
    private static ThreadLocal<Integer> threadLocalValue = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0; // 初始值设为0
        }
    };

    public static void main(String[] args) throws InterruptedException {
        // 启动两个线程来展示ThreadLocal的作用
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                incrementAndPrint();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                incrementAndPrint();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join(); // 等待thread1执行完毕
        thread2.join(); // 等待thread2执行完毕

        System.out.println("Main thread final value: " + threadLocalValue.get());
    }

    /**
     * 自增并打印当前线程的ThreadLocal值
     */
    private static void incrementAndPrint() {
        int currentValue = threadLocalValue.get();
        threadLocalValue.set(currentValue + 1);
        System.out.println(Thread.currentThread().getName() + ": " + threadLocalValue.get());
    }
}

6.2. ThreadFactory

线程工厂,自定义创建线程(设置名称、优先级、守护线程)

6.3. Callable / Future / FutureTask

  • Callable:带返回值、可抛异常的任务
  • Future:获取任务执行结果、取消任务
  • FutureTask:包装 Callable,可提交给线程池

6.4. CompletableFuture

JDK8 新增,异步编排神器 支持链式调用、多任务组合(串行、并行、聚合),简化异步编程


import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CompletableFutureExample {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建一个异步任务
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Hello from CompletableFuture!";
        });

        // 添加回调处理结果
        CompletableFuture<Void> result = future.thenAccept(System.out::println);

        // 等待所有任务完成
        result.join();

        System.out.println("Main thread continues...");
        CompletableFuture.runAsync()
    }
}

7、其他辅助类

7.1. TimeUnit

时间单位工具类,替代 Thread.sleep,可读性更强 TimeUnit.SECONDS.sleep(1)

7.2. LockSupport

底层线程阻塞 / 唤醒工具

  • park():阻塞线程
  • unpark(Thread):唤醒线程
  • 是 Lock、同步器的底层实现

快速记忆思维导图(极简版)

  1. 线程池:ThreadPoolExecutor、Executors、ScheduledExecutor
  2. 锁:ReentrantLock、ReentrantReadWriteLock
  3. 同步器:CountDownLatch、CyclicBarrier、Semaphore
  4. 并发集合:ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue
  5. 原子类:AtomicInteger、LongAdder
  6. 异步:Callable、Future、CompletableFuture
  7. 线程变量:ThreadLocal

总结

  • 生产开发优先用:线程池、ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue、原子类、CompletableFuture
  • 锁优先用:ReentrantLock、读写锁
  • 线程协作必用:CountDownLatch、CyclicBarrier、Semaphore
  • 所有工具都在 java.util.concurrent 包下,是 Java 并发编程的标准解决方案。