Java并发18:读写锁ReadWriteLock - 优化读多写少场景

引言:ReentrantLock的性能瓶颈 在上一篇文章中,我们学习了ReentrantLock,但它有一个性能问题: public class Cache { private final Map<String, String> map = new HashMap<>(); private final Lock lock = new ReentrantLock(); public String get(String key) { lock.lock(); // 读操作也要加锁 try { return map.get(key); } finally { lock.unlock(); } } public void put(String key, String value) { lock.lock(); // 写操作加锁 try { map.put(key, value); } finally { lock.unlock(); } } } 问题: 读操作(get)本身是线程安全的,多个线程可以同时读 但ReentrantLock是独占锁,同一时刻只有一个线程能持有 大量读操作被阻塞,性能差 解决方案:使用读写锁(ReadWriteLock) public class CacheWithReadWriteLock { private final Map<String, String> map = new HashMap<>(); private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); private final Lock readLock = rwLock.readLock(); private final Lock writeLock = rwLock.writeLock(); public String get(String key) { readLock.lock(); // 读锁(共享) try { return map.get(key); } finally { readLock.unlock(); } } public void put(String key, String value) { writeLock.lock(); // 写锁(独占) try { map.put(key, value); } finally { writeLock.unlock(); } } } 性能提升(10个线程,90%读操作): ...

2025-11-20 · maneng

Java并发17:Lock接口与ReentrantLock - 更灵活的锁

引言:synchronized的局限性 在前面的文章中,我们深入学习了synchronized,但它有一些局限性: public class SynchronizedLimitations { private final Object lock = new Object(); public void method() { synchronized (lock) { // 问题1:无法响应中断 // 如果获取锁的线程被阻塞,无法中断它 // 问题2:无法设置超时 // 如果获取不到锁,会一直等待 // 问题3:必须在同一个代码块中释放锁 // 无法在方法A获取,方法B释放 // 问题4:无法尝试非阻塞获取锁 // 无法tryLock() // 问题5:无法实现公平锁 // synchronized是非公平的 } } } JDK 1.5引入Lock接口,解决这些问题: Lock lock = new ReentrantLock(); // 可响应中断 lock.lockInterruptibly(); // 可设置超时 boolean success = lock.tryLock(1, TimeUnit.SECONDS); // 可尝试非阻塞获取 if (lock.tryLock()) { try { // ... } finally { lock.unlock(); } } // 可实现公平锁 Lock fairLock = new ReentrantLock(true); 本篇文章将深入Lock接口和ReentrantLock的实现原理。 ...

2025-11-20 · maneng

Java并发16:CAS算法与ABA问题 - 无锁编程的基石与陷阱

引言:原子类的秘密武器 在上一篇文章中,我们学习了AtomicInteger等原子类,它们的核心就是CAS操作: public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } // Unsafe中的实现 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); // 读取当前值 } while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS更新 return v; } 三个核心问题: CAS是如何实现的?(底层原理) CAS有什么问题?(ABA、自旋、单变量) 如何解决这些问题?(AtomicStampedReference等) 本篇文章将深入CAS算法的每个细节。 一、CAS算法的原理 1.1 CAS的定义 CAS(Compare-And-Swap):比较并交换 boolean CAS(内存地址V, 期望值A, 新值B) { if (V的值 == A) { V的值 = B; return true; // 更新成功 } else { return false; // 更新失败 } } 关键特性: 原子操作:整个比较和交换过程不可分割 硬件支持:由CPU指令保证原子性 无锁:不需要加锁,避免线程阻塞 1.2 CAS的工作流程 示例:两个线程同时执行count++ ...

2025-11-20 · maneng

Java并发15:原子类AtomicXXX详解 - 无锁的线程安全

引言:volatile不能保证原子性 回顾之前讲过的例子: public class Counter { private volatile int count = 0; public void increment() { count++; // 不是原子操作! } } 问题: count++; // 实际上是3个操作: // 1. temp = count (读) // 2. temp = temp + 1 (修改) // 3. count = temp (写) // 多线程执行时可能丢失更新 解决方案1:synchronized public synchronized void increment() { count++; // 原子操作 } // 缺点:性能开销大 解决方案2:原子类 private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子操作,性能好 } 性能对比: synchronized: 1200ms AtomicInteger: 280ms 性能提升: 4.3倍 本篇文章将深入Java原子类的实现原理和使用方法。 ...

2025-11-20 · maneng

Java并发14:synchronized的优化演进 - 从偏向锁到重量级锁

引言:synchronized为什么不慢了? 在JDK 1.5之前,synchronized被认为是"重量级锁",性能很差: // JDK 1.4时代 public synchronized void increment() { count++; // 即使无竞争,也要走完整的Monitor流程 } // 每次加锁/解锁都要陷入内核态,开销巨大 性能对比(JDK 1.4 vs JDK 1.8): JDK 1.4: 100万次synchronized: 约3000ms JDK 1.8: 100万次synchronized: 约50ms 性能提升60倍! 为什么提升这么大? 从JDK 1.6开始,HotSpot引入了锁优化技术: 偏向锁(Biased Locking) 轻量级锁(Lightweight Locking) 自旋锁(Spinning) 锁消除(Lock Elimination) 锁粗化(Lock Coarsening) 本篇文章将深入这些优化技术的原理和实现。 一、锁的四种状态 Java对象锁有4种状态,按级别从低到高: 无锁 → 偏向锁 → 轻量级锁 → 重量级锁 关键特性: 锁只能升级,不能降级(单向) 每种锁适用不同的竞争场景 1.1 Mark Word的锁状态 回顾Mark Word结构(64位JVM): 无锁状态 (001): ┌─────────────────────────────────────────────────────────────┐ │ unused(25) │ hashcode(31) │ unused(1) │ age(4) │ 0 │ 01 │ └─────────────────────────────────────────────────────────────┘ 偏向锁状态 (101): ┌─────────────────────────────────────────────────────────────┐ │ ThreadID(54) │ epoch(2) │ unused(1) │ age(4) │ 1 │ 01 │ └─────────────────────────────────────────────────────────────┘ 轻量级锁状态 (00): ┌─────────────────────────────────────────────────────────────┐ │ 指向栈中Lock Record的指针(62) │ 00 │ └─────────────────────────────────────────────────────────────┘ 重量级锁状态 (10): ┌─────────────────────────────────────────────────────────────┐ │ 指向Monitor对象的指针(62) │ 10 │ └─────────────────────────────────────────────────────────────┘ 锁状态判断: ...

2025-11-20 · maneng

Java并发13:synchronized原理与使用 - 重量级锁的前世今生

引言:从一个线程安全问题说起 看这个经典的银行转账问题: public class BankAccount { private int balance = 1000; public void transfer(BankAccount target, int amount) { this.balance -= amount; // 1. 扣款 target.balance += amount; // 2. 入账 } } // 两个线程同时转账 Thread t1 = new Thread(() -> accountA.transfer(accountB, 100)); Thread t2 = new Thread(() -> accountB.transfer(accountA, 200)); t1.start(); t2.start(); 问题:可能发生死锁或数据不一致! 解决方案:使用synchronized public synchronized void transfer(BankAccount target, int amount) { this.balance -= amount; target.balance += amount; } 三个疑问: synchronized是如何保证线程安全的? 为什么它能同时保证原子性、可见性、有序性? 它的性能开销来自哪里? 本篇文章将深入synchronized的底层原理,从对象头到Monitor机制,彻底理解Java最基础的同步机制。 一、synchronized的三种使用方式 1.1 修饰实例方法 public class Counter { private int count = 0; public synchronized void increment() { count++; } // 等价于: // public void increment() { // synchronized (this) { // count++; // } // } } 锁对象:当前实例(this) ...

2025-11-20 · maneng

Java并发12:volatile关键字深度解析 - 轻量级同步机制

引言:volatile能解决什么问题? 看这个经典的"停止线程"问题: public class StopThread { private boolean stop = false; // 没有volatile public void run() { new Thread(() -> { while (!stop) { // 执行任务 doWork(); } System.out.println("线程停止"); }).start(); // 1秒后停止线程 Thread.sleep(1000); stop = true; System.out.println("已设置stop=true"); } } 运行结果: 已设置stop=true (线程永远不会停止!) 加上volatile后: private volatile boolean stop = false; // 加volatile 运行结果: 已设置stop=true 线程停止 ← 正常停止了 三个问题: 为什么没有volatile时线程看不到stop = true? volatile做了什么让线程能看到了? volatile是万能的吗?什么时候不能用? 本篇文章将深入volatile的底层原理,彻底理解这个轻量级同步机制。 一、volatile解决的两大问题 1.1 可见性问题 问题根源:CPU缓存 CPU 0 CPU 1 ↓ ↓ L1 Cache (stop=false) L1 Cache (stop=false) ↓ ↓ 主内存 (stop=false) 时刻1: CPU 0修改stop=true CPU 0: L1 Cache (stop=true) ← 只在CPU 0的缓存中 CPU 1: L1 Cache (stop=false) ← CPU 1看不到! volatile的解决方案: ...

2025-11-20 · maneng

Java并发08:并发编程的三大核心问题 - 原子性、可见性、有序性

引言:为什么synchronized能解决所有问题? // volatile只解决部分问题 private volatile int count = 0; count++; // 仍然不安全! // synchronized解决所有问题 private int count = 0; public synchronized void increment() { count++; // 安全 } 为什么? 关键在于理解并发编程的三大核心问题: 原子性(Atomicity) 可见性(Visibility) 有序性(Ordering) 一、原子性(Atomicity) 1.1 什么是原子性? 定义:一个操作或多个操作,要么全部执行且执行过程不被打断,要么都不执行。 int a = 10; // ✅ 原子操作 a++; // ❌ 非原子操作(3条指令) 1.2 哪些操作是原子的? 原子操作: // ✅ 基本类型的读写(long/double除外) int a = 1; boolean b = true; // ✅ 引用类型的读写 Object obj = new Object(); // ✅ volatile变量的读写 volatile int count = 0; count = 1; // 原子的 非原子操作: // ❌ long/double(64位,需要两次操作) long value = 123L; // 非原子的(未加volatile) // ❌ 复合操作 count++; // read-modify-write array[index]++; // 非原子 // ❌ check-then-act if (map.get(key) == null) { map.put(key, value); // 竞态条件 } 1.3 如何保证原子性? 方式1:synchronized public synchronized void increment() { count++; // 整个方法是原子的 } 方式2:Lock private Lock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } 方式3:原子类 private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子操作 } 二、可见性(Visibility) 2.1 什么是可见性? 定义:当一个线程修改了共享变量,其他线程能够立即看到这个修改。 ...

2025-11-20 · maneng

Java并发11:happens-before原则 - JMM的核心规则

引言:如何判断程序是否线程安全? 看这段代码,能否确定线程安全? public class DataRace { private int data = 0; private boolean ready = false; // 线程1 public void writer() { data = 42; // 1 ready = true; // 2 } // 线程2 public void reader() { if (ready) { // 3 System.out.println(data); // 4 一定输出42吗? } } } 三个问题: 线程2能看到ready = true吗?(可见性) 如果看到ready = true,能保证看到data = 42吗?(有序性) 如何用形式化的规则判断? 传统方法是分析各种可能的执行顺序,但这太复杂了! JMM的解决方案:happens-before原则 happens-before是JMM的核心规则,它定义了: 什么时候一个操作的结果对另一个操作可见 什么时候两个操作不能重排序 如何建立正确的并发语义 掌握happens-before原则,就能快速判断程序是否线程安全。 一、happens-before的定义 1.1 形式化定义 happens-before关系(简写为 hb): 如果操作A happens-before 操作B,记作 A hb B,则: 可见性保证:A的结果对B可见 有序性保证:A在B之前执行(从程序语义角度) 注意: ...

2025-11-20 · maneng

生产级最佳实践:Java并发编程完整指南

一、核心原则 1.1 安全第一 // 1. 线程安全的优先级 // 正确性 > 性能 > 可读性 // ❌ 错误:追求性能,忽略安全 public class UnsafeCounter { private int count = 0; public void increment() { count++; // 非原子操作,线程不安全 } } // ✅ 正确:优先保证线程安全 public class SafeCounter { private final AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子操作,线程安全 } } 1.2 最小化同步范围 // ❌ 错误:同步范围过大 public synchronized void process() { prepareData(); // 无需同步 accessSharedData(); // 需要同步 cleanup(); // 无需同步 } // ✅ 正确:最小化同步范围 public void process() { prepareData(); synchronized (lock) { accessSharedData(); // 只同步必要代码 } cleanup(); } 1.3 不变性优于锁 // ❌ 复杂:使用锁保护可变对象 public class MutablePoint { private int x, y; public synchronized void setX(int x) { this.x = x; } public synchronized int getX() { return x; } } // ✅ 简单:使用不变对象 public final class ImmutablePoint { private final int x, y; public ImmutablePoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; // 无需同步 } } 二、线程与线程池最佳实践 2.1 务必使用线程池 // ❌ 错误:直接创建线程 for (int i = 0; i < 10000; i++) { new Thread(() -> task()).start(); // 线程数爆炸 } // ✅ 正确:使用线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor( 10, 20, // 核心线程数、最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder() .setNameFormat("business-pool-%d") .build(), new ThreadPoolExecutor.CallerRunsPolicy() ); for (int i = 0; i < 10000; i++) { executor.submit(() -> task()); } 2.2 线程池参数计算 // CPU密集型任务 int cpuCount = Runtime.getRuntime().availableProcessors(); int corePoolSize = cpuCount + 1; // I/O密集型任务 int corePoolSize = cpuCount * 2; // 混合型任务(推荐公式) // corePoolSize = N * (1 + WT/ST) // N = CPU核心数 // WT = 等待时间 // ST = 计算时间 int corePoolSize = cpuCount * (1 + waitTime / computeTime); // 队列容量 int queueCapacity = peakQPS * avgExecutionTime; // 最大线程数 int maximumPoolSize = corePoolSize * 2; 2.3 线程命名 // ✅ 使用ThreadFactory自定义线程名 ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("business-pool-%d") .setDaemon(false) .setPriority(Thread.NORM_PRIORITY) .setUncaughtExceptionHandler((t, e) -> { log.error("线程异常:" + t.getName(), e); }) .build(); ThreadPoolExecutor executor = new ThreadPoolExecutor( 10, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), threadFactory, new ThreadPoolExecutor.CallerRunsPolicy() ); 三、锁的最佳实践 3.1 锁的选择 // 1. 读多写少:StampedLock StampedLock sl = new StampedLock(); long stamp = sl.tryOptimisticRead(); // 读取数据 if (!sl.validate(stamp)) { stamp = sl.readLock(); try { // 重新读取 } finally { sl.unlockRead(stamp); } } // 2. 公平性要求:ReentrantLock(true) Lock lock = new ReentrantLock(true); // 3. 简单场景:synchronized synchronized (lock) { // 业务逻辑 } // 4. 高并发计数:LongAdder LongAdder counter = new LongAdder(); counter.increment(); 3.2 锁的粒度 // ❌ 粗粒度锁:性能差 public synchronized void process(String key, String value) { map.put(key, value); // 所有key共用一个锁 } // ✅ 细粒度锁:性能好 private final ConcurrentHashMap<String, Lock> lockMap = new ConcurrentHashMap<>(); public void process(String key, String value) { Lock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock()); lock.lock(); try { map.put(key, value); // 每个key独立锁 } finally { lock.unlock(); } } 3.3 避免死锁 // ✅ 固定加锁顺序 public void transfer(Account from, Account to, int amount) { Account first, second; if (from.getId() < to.getId()) { first = from; second = to; } else { first = to; second = from; } synchronized (first) { synchronized (second) { // 转账逻辑 } } } // ✅ 使用tryLock超时 if (lock1.tryLock(1, TimeUnit.SECONDS)) { try { if (lock2.tryLock(1, TimeUnit.SECONDS)) { try { // 业务逻辑 } finally { lock2.unlock(); } } } finally { lock1.unlock(); } } 四、并发集合最佳实践 4.1 集合选择 场景 推荐集合 理由 读多写少 CopyOnWriteArrayList 读无锁,性能高 高并发Map ConcurrentHashMap 分段锁,性能好 生产者-消费者 BlockingQueue 自带阻塞,简化代码 优先级队列 PriorityBlockingQueue 支持优先级 延迟队列 DelayQueue 支持延迟 4.2 ConcurrentHashMap正确用法 ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // ❌ 错误:组合操作不原子 if (!map.containsKey(key)) { map.put(key, value); // 线程不安全 } // ✅ 正确:使用原子方法 map.putIfAbsent(key, value); // ✅ 原子更新 map.compute(key, (k, v) -> (v == null ? 0 : v) + 1); // ✅ 原子替换 map.replace(key, oldValue, newValue); 五、异步编程最佳实践 5.1 CompletableFuture // ✅ 务必指定线程池 ExecutorService executor = Executors.newFixedThreadPool(10); CompletableFuture.supplyAsync(() -> { return queryData(); }, executor) // 指定线程池 .thenApplyAsync(data -> { return processData(data); }, executor) .exceptionally(ex -> { log.error("异步任务失败", ex); return defaultValue; }) .thenAccept(result -> { log.info("结果:{}", result); }); // ✅ 并行查询 CompletableFuture<UserInfo> userFuture = CompletableFuture.supplyAsync(() -> queryUser(), executor); CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(() -> queryOrders(), executor); CompletableFuture.allOf(userFuture, orderFuture) .thenApply(v -> { UserInfo user = userFuture.join(); List<Order> orders = orderFuture.join(); return new UserDetailDTO(user, orders); }); 5.2 超时控制 // ✅ 设置超时 CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return slowQuery(); }, executor); try { String result = future.get(1, TimeUnit.SECONDS); } catch (TimeoutException e) { log.error("查询超时"); return defaultValue; } // ✅ Java 9+:orTimeout future.orTimeout(1, TimeUnit.SECONDS) .exceptionally(ex -> defaultValue); 六、生产环境配置 6.1 JVM参数 # 通用配置 -Xms4g -Xmx4g # 堆内存 -Xss1m # 线程栈 -XX:+UseG1GC # 使用G1垃圾回收器 -XX:MaxGCPauseMillis=200 # GC暂停时间目标 -XX:ParallelGCThreads=8 # 并行GC线程数 -XX:ConcGCThreads=2 # 并发GC线程数 # 偏向锁(低竞争场景) -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 # 容器环境 -XX:ActiveProcessorCount=2 # 显式指定CPU核心数 -Djava.util.concurrent.ForkJoinPool.common.parallelism=2 # 监控与调试 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/heapdump.hprof -Xloggc:/var/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps 6.2 Spring Boot配置 # application.yml server: tomcat: threads: max: 200 # 最大线程数 min-spare: 10 # 最小空闲线程数 accept-count: 100 # 等待队列长度 max-connections: 10000 # 最大连接数 spring: task: execution: pool: core-size: 10 max-size: 20 queue-capacity: 1000 thread-name-prefix: async-pool- 七、监控与告警 7.1 核心监控指标 // 1. 线程池监控 public class ThreadPoolMonitor { @Scheduled(fixedRate = 5000) public void monitor() { // 活跃线程数 int activeCount = executor.getActiveCount(); // 队列大小 int queueSize = executor.getQueue().size(); // 线程利用率 double threadUtilization = (double) activeCount / executor.getPoolSize() * 100; // 队列使用率 double queueUtilization = (double) queueSize / queueCapacity * 100; // 告警 if (threadUtilization > 90) { alert("线程池利用率过高:" + threadUtilization + "%"); } if (queueUtilization > 80) { alert("队列积压严重:" + queueUtilization + "%"); } } } 7.2 Prometheus + Grafana // 使用Micrometer导出指标 MeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); // 监控线程池 ExecutorServiceMetrics.monitor(registry, executor, "business-pool", "app", "my-app"); // 访问指标 // http://localhost:8080/actuator/prometheus 八、问题排查清单 8.1 CPU 100% 1. top -Hp <pid> # 找到CPU高的线程ID 2. printf "%x\n" <tid> # 转换为16进制 3. jstack <pid> | grep "0x<hex-id>" # 查看堆栈 4. 定位代码 → 修复问题 8.2 死锁 1. jstack <pid> | grep "Found one Java-level deadlock" 2. 分析等待链 3. 修复锁顺序 8.3 线程泄漏 1. jstack <pid> | wc -l # 查看线程数 2. jmap -dump:file=heap.hprof <pid> 3. MAT分析Thread对象 4. 定位泄漏点 九、代码审查检查项 9.1 必查项 是否使用线程池? 线程池是否指定线程名? 线程池是否配置拒绝策略? 是否有死锁风险? 是否正确处理中断? 是否有资源泄漏? 异常是否被正确捕获? 是否使用了正确的锁? 锁的粒度是否合理? 是否使用了线程安全的集合? 9.2 性能优化项 读多写少场景是否使用读写锁? 高并发计数是否使用LongAdder? 是否使用了不变对象? 是否最小化同步范围? 是否避免了锁竞争? 十、核心知识图谱 10.1 并发基础 线程基础 ├── 线程创建(Thread、Runnable、Callable) ├── 线程状态(NEW、RUNNABLE、BLOCKED、WAITING、TERMINATED) ├── 线程中断(interrupt、isInterrupted、interrupted) └── 线程通信(wait、notify、notifyAll) 10.2 内存模型 JMM(Java Memory Model) ├── 可见性(volatile、synchronized) ├── 有序性(happens-before) ├── 原子性(AtomicInteger、synchronized) └── CPU缓存(缓存一致性、伪共享) 10.3 同步工具 锁 ├── synchronized(偏向锁、轻量级锁、重量级锁) ├── ReentrantLock(公平锁、非公平锁、可中断) ├── ReadWriteLock(读锁、写锁) └── StampedLock(乐观读、悲观读、写锁) 原子类 ├── AtomicInteger(CAS) ├── LongAdder(分段累加) └── AtomicReference(对象原子操作) 并发集合 ├── ConcurrentHashMap(分段锁、CAS) ├── CopyOnWriteArrayList(读写分离) └── BlockingQueue(阻塞队列) 同步器 ├── CountDownLatch(倒计时) ├── CyclicBarrier(循环栅栏) ├── Semaphore(信号量) └── Phaser(多阶段同步) 10.4 线程池 ThreadPoolExecutor ├── 核心参数(corePoolSize、maximumPoolSize、keepAliveTime) ├── 工作队列(ArrayBlockingQueue、LinkedBlockingQueue) ├── 拒绝策略(AbortPolicy、CallerRunsPolicy) └── 线程工厂(ThreadFactory) 特殊线程池 ├── ScheduledThreadPoolExecutor(定时任务) ├── ForkJoinPool(工作窃取) └── CompletableFuture(异步编程) 十一、学习路径总结 11.1 基础篇(1-10篇) 为什么需要并发 进程与线程 线程生命周期 线程创建方式 线程中断机制 线程通信 线程安全问题 可见性、有序性、原子性 CPU缓存与多核 JMM与happens-before 11.2 原理篇(11-18篇) happens-before规则 volatile原理 synchronized原理 synchronized优化 原子类AtomicInteger CAS与ABA Lock与ReentrantLock ReadWriteLock读写锁 11.3 工具篇(19-28篇) 线程池原理 ThreadPoolExecutor详解 线程池最佳实践 BlockingQueue阻塞队列 ConcurrentHashMap CountDownLatch与CyclicBarrier Semaphore与Exchanger Phaser多阶段同步 CopyOnWriteArrayList CompletableFuture异步编程 11.4 实战篇(29-33篇) CompletableFuture实战 ForkJoinPool工作窃取 无锁编程与LongAdder StampedLock性能优化 并发设计模式 11.5 排查篇(34-39篇) 死锁的产生与排查 线程池监控与调优 JVM线程相关参数 并发问题排查工具 JMH性能测试 生产级最佳实践(本篇) 总结 Java并发编程是一个复杂但重要的技术领域,掌握并发编程需要: ...

2025-11-20 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...