分布式、高并发-Day04

[复制链接]
发表于 2025-9-17 20:53:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
以下是 Day 4 具体学习内容(CAS 与原子操作实战,30 分钟完备筹划),包罗原理剖析、分步代码实战和性能对比:
📖 本日学习目标


  • 把握 CAS(Compare-And-Swap)无锁算法的核心原理
  • 学会使用AtomicInteger实现线程安全的计数器
  • 理解 ABA 题目及办理方案(AtomicStampedReference)
⏰ 时间分配

时间段任务具体内容0-10 分钟理论:CAS 原理与原子类1. CAS 三要素:内存值 (V)、旧值 (A)、新值 (B)2. AtomicInteger底层实现3. ABA 题目演示与办理10-25 分钟实战:无锁计数器对比实验1. 用 CAS 实现线程安全计数器2. 用synchronized实现同步计数器3. 对比两种方式的性能与资源占用25-30 分钟总结与扩展1. 记载 CAS 的上风与适用场景2. 思考:为什么 CAS 比synchronized更高效?3. 扩展:如何用 CAS 实现自界说原子操作?🔍 理论详解:CAS 核心概念


  • CAS 是什么?


  • 全称:Compare-And-Swap(比力并交换)
  • 核心逻辑:

    • 仅当内存中的值 V 即是预期旧值 A 时,才将其更新为新值 B,否则不做任何操作。

  1. // CAS伪代码
  2. boolean cas(V, A, B) {
  3.     if (V == A) {
  4.         V = B; // 原子操作,由CPU硬件保证
  5.         return true;
  6.     }
  7.     return false;
  8. }
复制代码
**上风:**无锁编程,克制线程壅闭(上下文切换斲丧),得当竞争不猛烈的场景。
2. ABA 题目与办理方案

  • 题目场景:

    • 线程 1 读取值为 A,线程 2 将其改为 B,再改回 A,线程 1 实行 CAS 时发现值照旧 A,误以为未被修改。

  • 办理方案:

    • 使用AtomicStampedReference,在值之外附加一个版本号(时间戳),每次修改版本号递增:

  1. AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
  2. int stamp = ref.getStamp(); // 获取初始版本号
  3. ref.compareAndSet(100, 200, stamp, stamp + 1); // 版本号必须匹配才成功
复制代码

  • 原子类家族
类名作用底层实现AtomicInteger整数原子操作Unsafe 类的 CAS 方法AtomicLong长整型原子操作同上AtomicReference对象引用原子操作CAS 操尴尬刁难象地点💻 实战步调:无锁计数器对比实验


  • 实验 1:用 CAS 实现计数器(AtomicInteger)
  1. import java.util.concurrent.atomic.AtomicInteger;
  2. public class CASCounter {
  3.     private AtomicInteger count = new AtomicInteger(0);
  4.     public void increment() {
  5.         count.incrementAndGet(); // 底层调用CAS
  6.     }
  7.     public int getCount() {
  8.         return count.get();
  9.     }
  10.     public static void main(String[] args) throws InterruptedException {
  11.         CASCounter counter = new CASCounter();
  12.         Thread[] threads = new Thread[10];
  13.         for (int i = 0; i < 10; i++) {
  14.             threads[i] = new Thread(() -> {
  15.                 for (int j = 0; j < 10000; j++) {
  16.                     counter.increment();
  17.                 }
  18.             });
  19.         }
  20.         for (Thread t : threads) {
  21.             t.start();
  22.         }
  23.         for (Thread t : threads) {
  24.             t.join();
  25.         }
  26.         System.out.println("CAS计数器结果:" + counter.getCount()); // 预期:100000
  27.     }
  28. }
复制代码

  • 实验 2:用synchronized实现同步计数器
  1. public class SynchronizedCounter {
  2.     private int count = 0;
  3.     public synchronized void increment() {
  4.         count++;
  5.     }
  6.     public int getCount() {
  7.         return count;
  8.     }
  9.     public static void main(String[] args) throws InterruptedException {
  10.         SynchronizedCounter counter = new SynchronizedCounter();
  11.         Thread[] threads = new Thread[10];
  12.         for (int i = 0; i < 10; i++) {
  13.             threads[i] = new Thread(() -> {
  14.                 for (int j = 0; j < 10000; j++) {
  15.                     counter.increment();
  16.                 }
  17.             });
  18.         }
  19.         for (Thread t : threads) {
  20.             t.start();
  21.         }
  22.         for (Thread t : threads) {
  23.             t.join();
  24.         }
  25.         System.out.println("Synchronized计数器结果:" + counter.getCount()); // 预期:100000
  26.     }
  27. }
复制代码

  • 性能对比(选做,5 分钟)


  • 添加计期间码:
  1. long start = System.currentTimeMillis();
  2. // 执行计数逻辑
  3. long end = System.currentTimeMillis();
  4. System.out.println("耗时:" + (end - start) + "ms");
复制代码

  • 预期效果:
  • CAS 版本:耗时更短(无锁,淘汰上下文切换)
  • Synchronized 版本:耗时较长(锁竞争导致线程壅闭)
📝 本日总结与扩展


  • 核心知识点速记
特性CAS(AtomicInteger)synchronized锁机制无锁(乐观锁)有锁(灰心锁)适用场景低竞争场景(如计数、状态标志)高竞争场景(如临界资源掩护)性能高(淘汰线程壅闭)低(可能触发锁升级)ABA 题目需AtomicStampedReference办理无(锁包管原子性)

  • 扩展思考(5 分钟)


  • 题目 1:CAS 操作会导致 “忙等待” 吗?
    答案:是的,CAS 失败时会循环重试(自旋),假如长时间不成功,反而比synchronized更耗 CPU。
  • 题目 2:生产环境如何选择 CAS 照旧锁?
    提示:
    读多写少、竞争低:优先用 CAS(如计数器、设置开关)
    写多读少、竞争高:优先用synchronized或ReentrantLock
🔧 工具与环境准备

代码要求:直接复制两个 Java 文件,无需额外依赖(JDK 1.8+)
运行验证:
确保两个步伐输出均为 100000(线程安全验证通过)
观察控制台是否有非常(如 ABA 题目未办理时可能出现数据错误)
✅ 本日任务 checklist

✅ 理解 CAS 的 “比力 - 交换” 核心逻辑
✅ 成功运行两个计数器步伐,验证线程安全性
✅ 记载 1 个 CAS 应用场景(如:分布式体系中的版本号控制)
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表