JUC(java.util.concurrent)包下常用的类
·
一、核心分类及常用类详解
1. 线程池相关(最核心,解决线程创建 / 销毁开销问题)
线程池是管理线程的容器,核心思想是复用线程,避免频繁创建销毁线程的性能损耗。
核心接口 / 类
| 类 / 接口 | 作用 |
|---|---|
Executor |
最顶层接口,定义了线程执行的核心方法execute(Runnable) |
ExecutorService |
继承Executor,扩展了线程池的生命周期管理(关闭、提交任务等) |
ThreadPoolExecutor |
线程池的核心实现类(推荐直接使用,而非Executors工具类) |
Executors |
线程池工具类,提供快速创建线程池的静态方法(注意:生产环境慎用) |
ScheduledExecutorService |
定时任务线程池接口,支持延迟 / 周期性执行任务 |
关键说明 & 示例
ThreadPoolExecutor 核心参数(新手必懂):
// 核心构造方法(7个参数)
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数(常驻线程,即使空闲也不销毁)
int maximumPoolSize, // 最大线程数(线程池能容纳的最大线程数)
long keepAliveTime, // 非核心线程空闲超时时间
TimeUnit unit, // 超时时间单位
BlockingQueue<Runnable> workQueue, // 任务队列(核心线程满时存放任务)
ThreadFactory threadFactory, // 线程创建工厂(自定义线程名称/优先级)
RejectedExecutionHandler handler // 拒绝策略(任务满时的处理方式)
)
基础使用示例(生产环境推荐写法):
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 自定义线程池(推荐)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
5, // 最大线程数
60, // 非核心线程空闲60秒销毁
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10), // 有界任务队列(避免内存溢出)
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:主线程执行
);
// 2. 提交任务
for (int i = 0; i < 10; i++) {
int taskId = i;
executor.execute(() -> {
System.out.println("任务" + taskId + "由线程" + Thread.currentThread().getName() + "执行");
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
});
}
// 3. 关闭线程池(必须!否则程序不会退出)
executor.shutdown();
}
}
Executors 工具类的坑:
newCachedThreadPool():无界线程池,可能创建大量线程导致 OOM;newFixedThreadPool():任务队列无界,任务过多会 OOM;- 生产环境优先用
ThreadPoolExecutor自定义参数,控制队列和线程数。
2. 锁相关(替代 synchronized,更灵活)
JUC 的锁基于Lock接口,相比synchronized(隐式锁),支持可中断、可超时、尝试获取锁、公平锁 / 非公平锁等特性。
核心类
| 类 | 作用 |
|---|---|
ReentrantLock |
可重入锁(和 synchronized 一样,同一线程可重复获取锁),支持公平 / 非公平 |
ReentrantReadWriteLock |
读写锁(读共享、写独占),适合读多写少场景,提升并发效率 |
示例:ReentrantLock(可中断锁)
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private static final ReentrantLock lock = new ReentrantLock(true); // 公平锁
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
// 尝试获取锁,5秒超时
if (lock.tryLock(5, TimeUnit.SECONDS)) {
System.out.println("线程1获取锁成功");
Thread.sleep(3000); // 持有锁3秒
} else {
System.out.println("线程1获取锁超时");
}
} catch (InterruptedException e) {
System.out.println("线程1获取锁时被中断");
Thread.currentThread().interrupt(); // 恢复中断状态
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock(); // 必须手动释放锁!
System.out.println("线程1释放锁");
}
}
});
Thread t2 = new Thread(() -> {
try {
lock.lockInterruptibly(); // 可中断的锁获取
System.out.println("线程2获取锁成功");
} catch (InterruptedException e) {
System.out.println("线程2获取锁时被中断");
Thread.currentThread().interrupt();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("线程2释放锁");
}
}
});
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt(); // 中断线程2的锁获取
}
}
读写锁示例(读多写少场景)
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private static final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private static final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private static int count = 0;
// 读方法(共享锁)
public static void read() {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "读取count:" + count);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
// 写方法(独占锁)
public static void write() {
writeLock.lock();
try {
count++;
System.out.println(Thread.currentThread().getName() + "写入count:" + count);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
// 3个读线程(可同时执行)
for (int i = 0; i < 3; i++) {
new Thread(ReadWriteLockDemo::read, "读线程" + i).start();
}
// 1个写线程(独占,读线程需等待)
new Thread(ReadWriteLockDemo::write, "写线程").start();
}
}
3. 并发集合(线程安全,替代 Vector/Hashtable)
JUC 的并发集合相比传统线程安全集合(如 Vector),采用分段锁、CAS、写时复制等机制,并发效率更高。
核心类
| 类 | 作用 | 适用场景 |
|---|---|---|
ConcurrentHashMap |
高效并发 Map(JDK1.8 用 CAS+Synchronized 替代分段锁) | 高并发读写 Map |
CopyOnWriteArrayList |
写时复制列表(读无锁,写复制数组) | 读多写少的列表场景 |
CopyOnWriteArraySet |
基于 CopyOnWriteArrayList 实现的并发 Set | 读多写少的 Set 场景 |
BlockingQueue |
阻塞队列(核心接口,支持入队 / 出队阻塞) | 生产者 - 消费者模型 |
ArrayBlockingQueue |
有界数组阻塞队列(固定容量) | 有界生产消费 |
LinkedBlockingQueue |
链表阻塞队列(默认无界,可指定容量) | 无界 / 有界生产消费 |
SynchronousQueue |
同步队列(无存储,生产必须等消费) | 线程池(newCachedThreadPool) |
阻塞队列示例(生产者 - 消费者)
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
// 生产者
static class Producer implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
queue.put(i); // 队列满时阻塞
System.out.println("生产者生产:" + i + ",队列大小:" + queue.size());
Thread.sleep(200);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// 消费者
static class Consumer implements Runnable {
@Override
public void run() {
try {
while (true) {
Integer num = queue.take(); // 队列空时阻塞
System.out.println("消费者消费:" + num + ",队列大小:" + queue.size());
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
}
4. 同步工具类(协调线程执行顺序)
用于控制多个线程之间的协作,比如等待所有线程完成、限制并发数等。
核心类
| 类 | 作用 | 核心区别 |
|---|---|---|
CountDownLatch |
倒计时门闩(一个线程等待多个线程完成,计数减到 0 后唤醒) | 计数只能减,不可重置 |
CyclicBarrier |
循环栅栏(多个线程互相等待,都到达栅栏后一起执行,计数可重置) | 可循环使用,支持屏障动作 |
Semaphore |
信号量(控制同时访问资源的线程数,支持公平 / 非公平) | 限流、控制并发数 |
Exchanger |
交换器(两个线程交换数据,仅支持两个线程) | 线程间数据交换 |
示例 1:CountDownLatch(等待所有子线程完成)
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int threadNum = 3;
CountDownLatch latch = new CountDownLatch(threadNum); // 计数3
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "执行任务");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 计数减1
System.out.println(Thread.currentThread().getName() + "任务完成,剩余计数:" + latch.getCount());
}
}, "线程" + i).start();
}
latch.await(); // 主线程等待计数为0
System.out.println("所有子线程完成,主线程继续执行");
}
}
示例 2:Semaphore(限流)
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
// 模拟只有2个停车位
private static final Semaphore semaphore = new Semaphore(2);
public static void main(String[] args) {
// 模拟5辆车抢车位
for (int i = 0; i < 5; i++) {
int carNum = i;
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可(车位),无许可则阻塞
System.out.println("车辆" + carNum + "抢到车位");
Thread.sleep(2000); // 停车2秒
System.out.println("车辆" + carNum + "离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可
}
}).start();
}
}
}
5. 原子类(无锁并发,基于 CAS)
原子类通过CAS(Compare And Swap,比较并交换) 实现无锁并发,相比锁机制,减少了线程上下文切换的开销,适合简单变量的并发更新。
核心类
| 类 | 作用 |
|---|---|
AtomicInteger/AtomicLong |
原子更新 int/long 类型变量 |
AtomicBoolean |
原子更新 boolean 类型 |
AtomicReference |
原子更新引用类型(对象) |
AtomicStampedReference |
原子更新引用类型,带版本号(解决 CAS 的 ABA 问题) |
示例:AtomicInteger(无锁累加)
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerDemo {
private static final AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
count.incrementAndGet(); // 原子自增(等价于count++,但线程安全)
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终计数:" + count.get()); // 输出2000(线程安全)
}
}
ABA 问题说明:
- 场景:线程 1 准备将变量从 A 改为 B,但线程 2 先将 A 改为 C,再改回 A,线程 1 的 CAS 会误以为值未变,更新成功;
- 解决:
AtomicStampedReference通过版本号(戳记)判断,只要版本号变了,即使值相同,CAS 也会失败。
二、总结
关键点回顾
- 核心分类:JUC 包常用类主要分为 5 类 —— 线程池、锁、并发集合、同步工具类、原子类,覆盖了并发编程的核心场景;
- 核心优势:相比传统并发方式(synchronized、Thread),JUC 提供了更高的并发效率(如 CAS、读写锁)、更灵活的控制(如可中断锁、超时锁)、更安全的工具(如有界阻塞队列);
- 使用原则:
- 线程池优先用
ThreadPoolExecutor自定义参数,避免Executors的无界风险; - 读多写少用
ReentrantReadWriteLock/CopyOnWriteArrayList,普通互斥用ReentrantLock; - 简单变量并发更新用原子类,复杂同步用锁或同步工具类;
- 生产消费模型优先用
BlockingQueue。
- 线程池优先用
更多推荐




所有评论(0)