JUC包概览
java.util.concurrent
(简称 juc
)包是 Java 提供的用于并发编程的工具包,包含了大量的并发工具、锁、同步器和集合,极大地简化了并发编程。以下是 juc
包中一些重要内容的详细解析:
1. 并发工具类
Executor 框架
1.1. Executor 接口
- 定义:这是一个顶级接口,定义了执行任务的标准方法。
- 方法:
void execute(Runnable command);
- 作用:用于将任务提交给执行者执行。
1.2. ExecutorService 接口
- 扩展:扩展了 Executor 接口,提供了管理终止和跟踪异步任务执行的功能。
- 主要方法:
void shutdown();
:启动有序关闭,不接受新任务。List<Runnable> shutdownNow();
:尝试停止所有正在执行的任务,并返回等待执行的任务列表。Future<?> submit(Runnable task);
:提交一个 Runnable 任务,返回一个 Future 表示任务的状态。Future<T> submit(Callable<T> task);
:提交一个 Callable 任务,返回一个 Future 表示任务的状态和结果。
1.3. ScheduledExecutorService 接口
- 扩展:扩展了 ExecutorService 接口,允许任务在延迟后或定期执行。
- 主要方法:
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
:在给定延迟后执行任务。ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
:以固定的周期执行任务。ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
:在每次执行完任务后,等待给定延迟再执行任务。
1.4. ThreadPoolExecutor 类
- 实现:一个强大的线程池实现类,允许定制线程池的行为。
- 构造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue);
- 主要参数:
corePoolSize
:核心线程数。maximumPoolSize
:最大线程数。keepAliveTime
:非核心线程的存活时间。unit
:时间单位。workQueue
:任务队列。
1.5. Executors 工厂类
- 作用:用于创建各种常用的 ExecutorService 实现。
- 常用方法:
Executors.newFixedThreadPool(int nThreads);
:创建一个固定线程数的线程池。Executors.newCachedThreadPool();
:创建一个可缓存的线程池。Executors.newSingleThreadExecutor();
:创建一个单线程的线程池。Executors.newScheduledThreadPool(int corePoolSize);
:创建一个支持定时及周期性任务执行的线程池。
示例代码
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(() -> System.out.println("Task executed"));
executorService.shutdown();
这个示例代码展示了如何使用 Executors
工厂类创建一个固定线程池,并提交一个任务执行,最后关闭线程池。
2. 同步器
- CountDownLatch
- 用于多个线程等待某些条件完成后再继续执行。
- 示例:多个线程等待主线程完成某些初始化工作。
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
// 模拟工作
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown();
}
}).start();
}
latch.await(); // 主线程等待
System.out.println("All threads have finished");
- CyclicBarrier
- 允许一组线程互相等待,直到所有线程都到达某个屏障点。
- 示例:在并行计算中使用,所有线程必须同步完成某个阶段工作后才能进入下一个阶段。
int parties = 3;
CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("All parties have arrived"));
for (int i = 0; i < parties; i++) {
new Thread(() -> {
try {
Thread.sleep(1000); // 模拟工作
barrier.await();
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}).start();
}
- Phaser
- 用途:Phaser 是一个多阶段的栅栏,相当于 CyclicBarrier 的升级版,可用于分阶段任务的并发控制执行。
- 主要方法:
int register();
:增加一个任务数,返回当前阶段号。int arrive();
:到达当前阶段,不等待其他线程。int arriveAndAwaitAdvance();
:到达当前阶段,并等待其他线程到达。int arriveAndDeregister();
:到达当前阶段,并减少一个任务数。
- 示例:
Phaser phaser = new Phaser(1); // 注册主线程
for (int i = 0; i < 3; i++) {
phaser.register(); // 注册子线程
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 开始阶段 1");
phaser.arriveAndAwaitAdvance(); // 阶段 1 完成
System.out.println(Thread.currentThread().getName() + " 开始阶段 2");
phaser.arriveAndAwaitAdvance(); // 阶段 2 完成
}).start();
}
phaser.arriveAndAwaitAdvance(); // 主线程等待阶段 1 完成
System.out.println("所有线程完成阶段 1");
phaser.arriveAndAwaitAdvance(); // 主线程等待阶段 2 完成
System.out.println("所有线程完成阶段 2");
- Semaphore
- 控制同时访问特定资源的线程数量。
- 示例:限制对某个资源(如数据库连接)的访问。
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
// 访问资源
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release();
}
}).start();
}
- Exchanger
- 两个线程可以交换数据的同步点。
- 示例:生产者和消费者线程交换数据。
Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
try {
String data = "Data from Thread 1";
String received = exchanger.exchange(data);
System.out.println("Thread 1 received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
new Thread(() -> {
try {
String data = "Data from Thread 2";
String received = exchanger.exchange(data);
System.out.println("Thread 2 received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
3. 锁和同步
- ReentrantLock
- 可重入锁,与
synchronized
关键字类似,但提供了更灵活的锁定操作。 - 支持公平锁和非公平锁。
- 可重入锁,与
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// 访问共享资源
} finally {
lock.unlock();
}
- ReentrantReadWriteLock
- 读写锁,允许多个读线程同时访问,但写线程独占访问。
- 适用于读多写少的场景。
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock();
try {
// 读操作
} finally {
rwLock.readLock().unlock();
}
rwLock.writeLock().lock();
try {
// 写操作
} finally {
rwLock.writeLock().unlock();
}
- StampedLock
- 提供了更高效的读写锁,支持乐观读。
- 适用于大量读操作且较少写操作的场景。
StampedLock stampedLock = new StampedLock();
long stamp = stampedLock.readLock();
try {
// 读操作
} finally {
stampedLock.unlockRead(stamp);
}
stamp = stampedLock.writeLock();
try {
// 写操作
} finally {
stampedLock.unlockWrite(stamp);
}
4. 并发集合
- ConcurrentHashMap
- 高效的线程安全的哈希表。
- 允许多个线程并发读写,适用于高并发场景。
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key1", 1);
Integer value = map.get("key1");
- ConcurrentSkipListMap
- 线程安全的有序映射,内部使用跳表实现,适用于需要排序的高并发场景。
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>();
map.put("key1", 1);
Integer value = map.get("key1");
- ConcurrentLinkedQueue
- 非阻塞的线程安全队列,适用于高并发场景。
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("element");
String element = queue.poll();
- ConcurrentLinkedDeque
- 线程安全的双端队列,适用于高并发场景,可以从两端进行插入和移除操作。
ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
deque.offerFirst("element");
String element = deque.pollLast();
- BlockingQueue 接口的实现类
- ArrayBlockingQueue:基于数组的有界阻塞队列。
- LinkedBlockingQueue:基于链表的可选有界阻塞队列。
- PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
- DelayQueue:支持延时获取元素的无界阻塞队列。
- SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作。
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("element");
String element = queue.take();
- CopyOnWriteArrayList
- 适用于读多写少的场景,读操作不需要加锁,写操作会创建副本。
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("element");
String element = list.get(0);
- ConcurrentSkipListSet
- 线程安全的有序集合,内部基于
ConcurrentSkipListMap
实现,适用于需要排序的高并发场景。
- 线程安全的有序集合,内部基于
ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<>();
set.add("element");
boolean contains = set.contains("element");
- CopyOnWriteArraySet
- 适用于读多写少的场景,内部使用
CopyOnWriteArrayList
实现,读操作不需要加锁,写操作会创建副本。
- 适用于读多写少的场景,内部使用
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("element");
boolean contains = set.contains("element");
5. 原子变量
java.util.concurrent.atomic 包提供了几种常见的原子变量类,原子变量类通过使用底层的 CAS(Compare-And-Swap)操作,提供了高效的线程安全操作,避免了传统锁机制带来的性能开销。
- AtomicInteger
- 提供了线程安全的整数操作。
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();
int value = atomicInteger.get();
- AtomicLong
- 提供了线程安全的长整数操作。
AtomicLong atomicLong = new AtomicLong(0L);
atomicLong.incrementAndGet();
long value = atomicLong.get();
- AtomicBoolean
- 提供了线程安全的布尔值操作。
AtomicBoolean atomicBoolean = new AtomicBoolean(false);
atomicBoolean.set(true);
boolean value = atomicBoolean.get();
- AtomicIntegerArray
- 提供了线程安全的整数数组操作。
AtomicIntegerArray atomicArray = new AtomicIntegerArray(10);
atomicArray.set(0, 1);
int value = atomicArray.get(0);
- AtomicLongArray
- 提供了线程安全的长整数数组操作。
AtomicLongArray atomicLongArray = new AtomicLongArray(10);
atomicLongArray.set(0, 1L);
long value = atomicLongArray.get(0);
- AtomicReferenceArray
- 提供了线程安全的引用类型数组操作。
AtomicReferenceArray<String> atomicReferenceArray = new AtomicReferenceArray<>(10);
atomicReferenceArray.set(0, "initial");
String value = atomicReferenceArray.get(0);
- AtomicStampedReference
- 提供了带有版本号的引用类型操作,解决了 CAS 操作中的 ABA 问题。
AtomicStampedReference<String> atomicStampedReference = new AtomicStampedReference<>("initial", 0);
int[] stampHolder = new int[1];
String value = atomicStampedReference.get(stampHolder);
atomicStampedReference.compareAndSet("initial", "updated", stampHolder[0], stampHolder[0] + 1);
- AtomicMarkableReference
- 提供了带有标记位的引用类型操作。
AtomicMarkableReference<String> atomicMarkableReference = new AtomicMarkableReference<>("initial", false);
boolean[] markHolder = new boolean[1];
String value = atomicMarkableReference.get(markHolder);
atomicMarkableReference.compareAndSet("initial", "updated", false, true);
- AtomicReference
- 提供了线程安全的引用操作。
AtomicReference<String> atomicReference = new AtomicReference<>("initial");
atomicReference.set("updated");
String value = atomicReference.get();
JUC
包通过这些类和工具,为开发者提供了强大的并发编程能力。使用这些工具,可以更高效地管理线程、安全地共享数据和构建高性能的并发应用程序。