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、同步器的底层实现
快速记忆思维导图(极简版)
- 线程池:ThreadPoolExecutor、Executors、ScheduledExecutor
- 锁:ReentrantLock、ReentrantReadWriteLock
- 同步器:CountDownLatch、CyclicBarrier、Semaphore
- 并发集合:ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue
- 原子类:AtomicInteger、LongAdder
- 异步:Callable、Future、CompletableFuture
- 线程变量:ThreadLocal
总结
- 生产开发优先用:线程池、ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue、原子类、CompletableFuture
- 锁优先用:ReentrantLock、读写锁
- 线程协作必用:CountDownLatch、CyclicBarrier、Semaphore
- 所有工具都在 java.util.concurrent 包下,是 Java 并发编程的标准解决方案。