跳到主要内容

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. BlockingQueue
64 */
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 设计原则

核心原则
  1. 优先使用不可变对象:避免状态变化带来的复杂性
  2. 最小化同步范围:只同步必要的代码块
  3. 使用线程安全的集合:避免手动同步
  4. 避免嵌套锁:防止死锁
  5. 正确使用线程池:避免频繁创建线程

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: 如何避免死锁?

答案:

  1. 固定锁顺序:所有线程按相同顺序获取锁
  2. 超时机制:使用tryLock设置超时时间
  3. 避免嵌套锁:减少锁的嵌套层次
  4. 使用并发工具:使用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 并发集合

集合类型线程安全实现特点适用场景
ListCopyOnWriteArrayList写时复制读多写少
SetConcurrentHashSet基于ConcurrentHashMap一般场景
MapConcurrentHashMap分段锁高并发场景
QueueArrayBlockingQueue有界阻塞队列生产者消费者
DequeConcurrentLinkedDeque无界双端队列高并发场景

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 性能优化趋势

  1. 无锁数据结构:减少锁竞争,提高性能
  2. 内存模型优化:利用硬件特性优化内存访问
  3. 异步编程:提高系统吞吐量
  4. 响应式编程:更好的资源利用

7. 总结

Java并发编程是构建高性能系统的核心技术,掌握并发编程需要深入理解:

7.1 核心要点

  1. 基础概念:线程、进程、并发、并行
  2. 同步机制:synchronized、Lock、原子类、volatile
  3. 线程管理:线程池、Executor框架
  4. 线程通信:wait/notify、Condition、BlockingQueue
  5. 并发工具:CountDownLatch、CyclicBarrier、Semaphore

7.2 最佳实践

  1. 设计原则:优先使用不可变对象、最小化同步范围
  2. 性能优化:减少锁竞争、使用读写锁、无锁编程
  3. 问题避免:防止死锁、处理竞态条件、保证可见性
  4. 工具选择:根据场景选择合适的并发工具

7.3 学习建议

  1. 理论结合实践:理解概念后多写代码验证
  2. 循序渐进:从简单示例开始,逐步增加复杂度
  3. 性能测试:对比不同实现方式的性能差异
  4. 持续学习:关注新的并发技术和最佳实践

通过深入理解和熟练运用这些并发编程技术,我们能够构建出更加高效、健壮和可维护的Java应用程序。

forum

评论区 / Comments