Java 并发编程总结
Java并发编程是构建高性能、高可用系统的核心技术。本文将对Java并发编程的核心知识进行全面总结,并提供实用的最佳实践和面试要点。
1. 并发编程核心概念
1.1 并发与并行
核心概念
- 并发(Concurrency):多个任务交替执行,在单核CPU上通过时间片轮转实现
- 并行(Parallelism):多个任务同时执行,需要多核CPU支持
| 特性 | 并发 | 并行 |
|---|---|---|
| 执行方式 | 交替执行 | 同时执行 |
| 硬件要求 | 单核即可 | 需要多核 |
| 资源竞争 | 存在 | 较少 |
| 实现复杂度 | 中等 | 较高 |
| 适用场景 | I/O密集型 | CPU密集型 |
1.2 线程安全级别
线程安全级别示例
java
1public class ThreadSafetyLevels {2 3 /**4 * 1. 不可变对象 - 最高级别线程安全5 */6 public static final class ImmutablePoint {7 private final int x;8 private final int y;9 10 public ImmutablePoint(int x, int y) {11 this.x = x;12 this.y = y;13 }14 15 public int getX() { return x; }16 public int getY() { return y; }17 }18 19 /**20 * 2. 无状态对象 - 天然线程安全21 */22 public static class StatelessCalculator {23 public int add(int a, int b) {24 return a + b;25 }26 }27 28 /**29 * 3. 有状态但线程安全的对象30 */31 public static class ThreadSafeCounter {32 private final AtomicInteger count = new AtomicInteger(0);33 34 public void increment() {35 count.incrementAndGet();36 }37 38 public int getCount() {39 return count.get();40 }41 }42 43 /**44 * 4. 有状态且非线程安全的对象45 */46 public static class UnsafeCounter {47 private int count = 0;48 49 public void increment() {50 count++; // 非原子操作51 }52 53 public int getCount() {54 return count;55 }56 }57}2. 并发编程核心技术
2.1 线程管理
| 技术 | 特点 | 适用场景 | 示例 |
|---|---|---|---|
| Thread | 基础线程类 | 简单任务 | new Thread(() -> {}).start() |
| Runnable | 任务接口 | 无返回值任务 | executor.submit(runnable) |
| Callable | 可返回值任务 | 需要返回结果 | executor.submit(callable) |
| ThreadPool | 线程复用 | 大量任务 | Executors.newFixedThreadPool(5) |
2.2 同步机制
同步机制对比
java
1public class SynchronizationMechanisms {2 3 /**4 * 1. synchronized 关键字5 */6 public static class SynchronizedExample {7 private int counter = 0;8 9 public synchronized void increment() {10 counter++;11 }12 13 public synchronized int getCounter() {14 return counter;15 }16 }17 18 /**19 * 2. Lock 接口20 */21 public static class LockExample {22 private final ReentrantLock lock = new ReentrantLock();23 private int counter = 0;24 25 public void increment() {26 lock.lock();27 try {28 counter++;29 } finally {30 lock.unlock();31 }32 }33 }34 35 /**36 * 3. 原子类37 */38 public static class AtomicExample {39 private final AtomicInteger counter = new AtomicInteger(0);40 41 public void increment() {42 counter.incrementAndGet();43 }44 45 public int getCounter() {46 return counter.get();47 }48 }49 50 /**51 * 4. volatile 关键字52 */53 public static class VolatileExample {54 private volatile boolean flag = false;55 56 public void setFlag() {57 flag = true;58 }59 60 public boolean getFlag() {61 return flag;62 }63 }64}2.3 线程通信
线程通信机制
java
1public class ThreadCommunication {2 3 /**4 * 1. wait/notify 机制5 */6 public static class WaitNotifyExample {7 private final Object lock = new Object();8 private boolean condition = false;9 10 public void waitForCondition() {11 synchronized (lock) {12 while (!condition) {13 try {14 lock.wait();15 } catch (InterruptedException e) {16 Thread.currentThread().interrupt();17 }18 }19 }20 }21 22 public void signalCondition() {23 synchronized (lock) {24 condition = true;25 lock.notify();26 }27 }28 }29 30 /**31 * 2. Condition 接口32 */33 public static class ConditionExample {34 private final ReentrantLock lock = new ReentrantLock();35 private final Condition condition = lock.newCondition();36 private boolean ready = false;37 38 public void await() {39 lock.lock();40 try {41 while (!ready) {42 condition.await();43 }44 } catch (InterruptedException e) {45 Thread.currentThread().interrupt();46 } finally {47 lock.unlock();48 }49 }50 51 public void signal() {52 lock.lock();53 try {54 ready = true;55 condition.signal();56 } finally {57 lock.unlock();58 }59 }60 }61 62 /**63 * 3. BlockingQueue64 */65 public static class BlockingQueueExample {66 private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);67 68 public void producer() {69 try {70 queue.put("message");71 } catch (InterruptedException e) {72 Thread.currentThread().interrupt();73 }74 }75 76 public String consumer() {77 try {78 return queue.take();79 } catch (InterruptedException e) {80 Thread.currentThread().interrupt();81 return null;82 }83 }84 }85}3. 并发编程最佳实践
3.1 设计原则
核心原则
- 优先使用不可变对象:避免状态变化带来的复杂性
- 最小化同步范围:只同步必要的代码块
- 使用线程安全的集合:避免手动同步
- 避免嵌套锁:防止死锁
- 正确使用线程池:避免频繁创建线程
3.2 性能优化策略
性能优化示例
java
1public class PerformanceOptimization {2 3 /**4 * 1. 减少锁竞争5 */6 public static class LockContentionOptimization {7 private final int segments = 16;8 private final Object[] locks = new Object[segments];9 private final int[] counters = new int[segments];10 11 public LockContentionOptimization() {12 for (int i = 0; i < segments; i++) {13 locks[i] = new Object();14 }15 }16 17 public void increment(int key) {18 int segment = Math.abs(key % segments);19 synchronized (locks[segment]) {20 counters[segment]++;21 }22 }23 }24 25 /**26 * 2. 使用读写锁27 */28 public static class ReadWriteOptimization {29 private final ReadWriteLock lock = new ReentrantReadWriteLock();30 private final Lock readLock = lock.readLock();31 private final Lock writeLock = lock.writeLock();32 private final Map<String, String> cache = new HashMap<>();33 34 public String get(String key) {35 readLock.lock();36 try {37 return cache.get(key);38 } finally {39 readLock.unlock();40 }41 }42 43 public void put(String key, String value) {44 writeLock.lock();45 try {46 cache.put(key, value);47 } finally {48 writeLock.unlock();49 }50 }51 }52 53 /**54 * 3. 无锁编程55 */56 public static class LockFreeProgramming {57 private final AtomicInteger counter = new AtomicInteger(0);58 59 public void increment() {60 counter.incrementAndGet();61 }62 63 public int getCount() {64 return counter.get();65 }66 }67}3.3 常见陷阱与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 死锁 | 多个线程互相等待 | 固定锁顺序、超时机制 |
| 活锁 | 线程不断重试失败 | 随机退避、改变策略 |
| 饥饿 | 某些线程无法获得资源 | 公平锁、优先级调整 |
| 竞态条件 | 非原子操作 | 同步机制、原子类 |
| 内存可见性 | 缓存不一致 | volatile、synchronized |
4. 并发编程面试要点
4.1 基础概念
Q1: 线程和进程的区别?
答案:
- 进程:操作系统分配资源的基本单位,有独立的内存空间
- 线程:CPU调度的基本单位,共享进程的内存空间
- 关系:一个进程可以包含多个线程,线程是进程的执行单元
Q2: synchronized和volatile的区别?
答案:
- synchronized:保证原子性、可见性和有序性,可以修饰方法和代码块
- volatile:只保证可见性和有序性,不能保证原子性,只能修饰变量
Q3: 什么是线程安全?
答案: 线程安全是指多线程环境下,程序能够正确执行,不会出现数据不一致或异常结果。
4.2 高级特性
Q4: 什么是CAS?有什么优缺点?
答案:
- CAS(Compare-And-Swap):比较并交换,是一种无锁算法
- 优点:性能高,无阻塞
- 缺点:ABA问题、自旋开销、只能保证一个变量的原子性
Q5: 什么是AQS?
答案:
- AQS(AbstractQueuedSynchronizer):抽象队列同步器
- 是Java并发包中锁和同步器的基础框架
- 提供了FIFO队列和状态管理机制
Q6: 线程池的核心参数有哪些?
答案:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:线程存活时间
- workQueue:工作队列
- threadFactory:线程工厂
- rejectedExecutionHandler:拒绝策略
4.3 实战问题
Q7: 如何实现一个线程安全的单例模式?
答案:
java
1public class Singleton {2 private volatile static Singleton instance;3 4 private Singleton() {}5 6 public static Singleton getInstance() {7 if (instance == null) {8 synchronized (Singleton.class) {9 if (instance == null) {10 instance = new Singleton();11 }12 }13 }14 return instance;15 }16}Q8: 如何避免死锁?
答案:
- 固定锁顺序:所有线程按相同顺序获取锁
- 超时机制:使用tryLock设置超时时间
- 避免嵌套锁:减少锁的嵌套层次
- 使用并发工具:使用ConcurrentHashMap等线程安全集合
Q9: 如何监控线程池状态?
答案:
java
1ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool;2System.out.println("核心线程数: " + executor.getCorePoolSize());3System.out.println("当前池大小: " + executor.getPoolSize());4System.out.println("活跃线程数: " + executor.getActiveCount());5System.out.println("队列大小: " + executor.getQueue().size());6System.out.println("已完成任务数: " + executor.getCompletedTaskCount());5. 并发编程工具类
5.1 并发集合
| 集合类型 | 线程安全实现 | 特点 | 适用场景 |
|---|---|---|---|
| List | CopyOnWriteArrayList | 写时复制 | 读多写少 |
| Set | ConcurrentHashSet | 基于ConcurrentHashMap | 一般场景 |
| Map | ConcurrentHashMap | 分段锁 | 高并发场景 |
| Queue | ArrayBlockingQueue | 有界阻塞队列 | 生产者消费者 |
| Deque | ConcurrentLinkedDeque | 无界双端队列 | 高并发场景 |
5.2 同步工具
同步工具示例
java
1public class SynchronizationTools {2 3 /**4 * 1. CountDownLatch - 倒计时门闩5 */6 public static class CountDownLatchExample {7 private final CountDownLatch latch = new CountDownLatch(3);8 9 public void worker() {10 try {11 // 执行工作12 Thread.sleep(1000);13 System.out.println("工作完成");14 latch.countDown();15 } catch (InterruptedException e) {16 Thread.currentThread().interrupt();17 }18 }19 20 public void waitForAllWorkers() {21 try {22 latch.await();23 System.out.println("所有工作完成");24 } catch (InterruptedException e) {25 Thread.currentThread().interrupt();26 }27 }28 }29 30 /**31 * 2. CyclicBarrier - 循环屏障32 */33 public static class CyclicBarrierExample {34 private final CyclicBarrier barrier = new CyclicBarrier(3, () -> {35 System.out.println("所有线程到达屏障");36 });37 38 public void worker() {39 try {40 System.out.println("线程到达屏障");41 barrier.await();42 System.out.println("线程继续执行");43 } catch (InterruptedException | BrokenBarrierException e) {44 Thread.currentThread().interrupt();45 }46 }47 }48 49 /**50 * 3. Semaphore - 信号量51 */52 public static class SemaphoreExample {53 private final Semaphore semaphore = new Semaphore(3);54 55 public void worker() {56 try {57 semaphore.acquire();58 System.out.println("获得许可,开始工作");59 Thread.sleep(1000);60 System.out.println("工作完成,释放许可");61 semaphore.release();62 } catch (InterruptedException e) {63 Thread.currentThread().interrupt();64 }65 }66 }67 68 /**69 * 4. Exchanger - 交换器70 */71 public static class ExchangerExample {72 private final Exchanger<String> exchanger = new Exchanger<>();73 74 public void producer() {75 try {76 String data = "生产者数据";77 String received = exchanger.exchange(data);78 System.out.println("生产者收到: " + received);79 } catch (InterruptedException e) {80 Thread.currentThread().interrupt();81 }82 }83 84 public void consumer() {85 try {86 String data = "消费者数据";87 String received = exchanger.exchange(data);88 System.out.println("消费者收到: " + received);89 } catch (InterruptedException e) {90 Thread.currentThread().interrupt();91 }92 }93 }94}6. 并发编程发展趋势
6.1 新技术趋势
| 技术 | 特点 | 应用场景 |
|---|---|---|
| CompletableFuture | 异步编程模型 | 复杂异步流程 |
| Fork/Join框架 | 分治并行计算 | 递归任务分解 |
| StampedLock | 乐观读锁 | 读多写少场景 |
| VarHandle | 变量句柄 | 低级别并发控制 |
| Project Loom | 虚拟线程 | 高并发I/O应用 |
6.2 性能优化趋势
- 无锁数据结构:减少锁竞争,提高性能
- 内存模型优化:利用硬件特性优化内存访问
- 异步编程:提高系统吞吐量
- 响应式编程:更好的资源利用
7. 总结
Java并发编程是构建高性能系统的核心技术,掌握并发编程需要深入理解:
7.1 核心要点
- 基础概念:线程、进程、并发、并行
- 同步机制:synchronized、Lock、原子类、volatile
- 线程管理:线程池、Executor框架
- 线程通信:wait/notify、Condition、BlockingQueue
- 并发工具:CountDownLatch、CyclicBarrier、Semaphore
7.2 最佳实践
- 设计原则:优先使用不可变对象、最小化同步范围
- 性能优化:减少锁竞争、使用读写锁、无锁编程
- 问题避免:防止死锁、处理竞态条件、保证可见性
- 工具选择:根据场景选择合适的并发工具
7.3 学习建议
- 理论结合实践:理解概念后多写代码验证
- 循序渐进:从简单示例开始,逐步增加复杂度
- 性能测试:对比不同实现方式的性能差异
- 持续学习:关注新的并发技术和最佳实践
通过深入理解和熟练运用这些并发编程技术,我们能够构建出更加高效、健壮和可维护的Java应用程序。
评论区 / Comments