什么是JUC
JUC(Java.util.concurrent)是 Java 中用于并发编程的工具包,它提供了一系列高效、可靠的并发编程工具,帮助开发者更好地处理多线程并发问题。
JUC中包含的内容
一、线程池(ThreadPoolExecutor)
-
概念和作用:
- 线程池是一种管理多线程的机制,它可以重复利用已创建的线程,减少线程创建和销毁的开销。通过预先创建一定数量的线程,当有任务需要执行时,从线程池中获取一个空闲线程来执行任务,任务完成后线程回到池中等待下一个任务,避免了频繁地创建和销毁线程对系统资源的浪费。
- 提高系统的响应速度和性能,尤其在处理大量短期任务时效果显著。
-
核心参数和使用方法:
-
corePoolSize(核心线程数):线程池中始终保持运行的线程数量。即使这些线程处于空闲状态,它们也不会被销毁,除非设置了allowCoreThreadTimeOut为true。 -
maximumPoolSize(最大线程数):线程池允许的最大线程数量。当任务队列已满且核心线程都在忙碌时,会创建新的线程直到达到这个数量。 -
keepAliveTime(线程存活时间):当线程数量超过核心线程数时,多余的空闲线程在多长时间内会被销毁。 -
unit(时间单位):与keepAliveTime配合使用,指定时间的单位,如秒、毫秒等。 -
workQueue(任务队列):用于存储等待执行的任务。常见的有LinkedBlockingQueue(无界队列)、ArrayBlockingQueue(有界队列)等。 -
threadFactory(线程工厂):用于创建新线程,可以设置线程的名称、优先级等属性。 -
RejectedExecutionHandler(拒绝策略):当任务队列已满且线程池无法再创建新线程时,用于处理无法接受的任务。常见的拒绝策略有AbortPolicy(直接抛出异常)、CallerRunsPolicy(由提交任务的线程自己执行任务)、DiscardPolicy(默默丢弃任务)、DiscardOldestPolicy(丢弃最老的任务,尝试重新提交当前任务)。 -
使用方法示例:
ExecutorService executorService = new ThreadPoolExecutor( 5, // 核心线程数 10, // 最大线程数 60L, TimeUnit.SECONDS, // 线程存活时间和单位 new LinkedBlockingQueue<>(), // 任务队列 new ThreadFactoryBuilder().setNameFormat("my-thread-%d").build(), // 线程工厂 new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略 executorService.execute(() -> { // 任务逻辑 }); -
二、并发容器
-
ConcurrentHashMap:
- 是一种高效的并发哈希表,允许多个线程同时进行读写操作而不需要外部同步。它通过分段锁(Segment)的方式实现了高效的并发访问,每个分段内部使用传统的哈希表结构,不同分段之间的操作可以并发进行,提高了整体的性能。
- 相比传统的
HashMap,在多线程环境下更加安全和高效,避免了HashMap在并发修改时可能出现的ConcurrentModificationException。
-
CopyOnWriteArrayList 和
CopyOnWriteArraySet:CopyOnWriteArrayList是一个线程安全的可变数组,它的主要特点是在进行写操作(如添加、删除元素)时,会复制一个新的数组,在新数组上进行修改,然后将原有的引用指向新数组,从而实现了读写分离。这种方式可以避免在迭代过程中被其他线程的修改影响,保证了迭代的线程安全。CopyOnWriteArraySet内部使用CopyOnWriteArrayList实现,是一个线程安全的集合,不允许有重复元素。
三、锁机制
1. ReentrantLock:
- 是一种可重入的互斥锁,与传统的
synchronized关键字类似,但提供了更多的高级功能。它支持尝试获取锁(tryLock)、可中断地获取锁(lockInterruptibly)以及支持公平锁和非公平锁的配置。 - 使用示例:
import java.util.concurrent.locks.ReentrantLock;
class MyClass {
private final ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
}
2. ReadWriteLock:
- 读写锁,允许多个线程同时读取共享资源,但在写操作时需要独占访问。它将锁分为读锁和写锁,提高了并发读的性能。
ReentrantReadWriteLock是 Java 中对读写锁的具体实现。
四、原子类(AtomicInteger、AtomicLong 等)
-
概念和作用:
- 原子类提供了对基本数据类型的原子操作,如自增、自减、赋值等。这些操作在多线程环境下是原子性的,不会被其他线程中断,确保了数据的一致性。
- 避免了使用传统的同步机制(如
synchronized)带来的性能开销,适用于需要频繁进行原子操作的场景。
-
使用方法示例:
import java.util.concurrent.atomic.AtomicInteger; class Counter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }
五、并发工具类
1. CountDownLatch:
- 一个同步辅助类,允许一个或多个线程等待其他一组线程完成操作后再继续执行。可以用来实现多个线程之间的等待和协调。
- 使用示例:
import java.util.concurrent.CountDownLatch;
class MyTask implements Runnable {
private final CountDownLatch latch;
public MyTask(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
// 任务逻辑
latch.countDown();
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
int threadCount = 5;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new MyTask(latch)).start();
}
latch.await();
System.out.println("All tasks completed.");
}
}
2. CyclicBarrier:
- 也是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。与
CountDownLatch不同的是,CyclicBarrier可以在到达屏障点后重新使用。 - 使用示例:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
class Worker implements Runnable {
private final CyclicBarrier barrier;
public Worker(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
// 任务逻辑
barrier.await();
// 后续任务
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
int threadCount = 5;
CyclicBarrier barrier = new CyclicBarrier(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Worker(barrier)).start();
}
}
}
3. Semaphore:
- 信号量,用于控制同时访问某个特定资源的线程数量。可以用来实现资源的有限访问,防止过多的线程同时竞争资源导致性能问题。
- 使用示例:
import java.util.concurrent.Semaphore;
class Resource {
private final Semaphore semaphore;
public Resource(int permits) {
semaphore = new Semaphore(permits);
}
public void useResource() throws InterruptedException {
semaphore.acquire();
try {
// 使用资源
} finally {
semaphore.release();
}
}
}
JUC 提供的这些工具极大地丰富了 Java 并发编程的手段,使得开发者能够更加高效、可靠地处理多线程并发问题,提高程序的性能和可扩展性。