JVM与性能调优:JVM基础与原理之Java内存模型(JMM)与并发基础(2)

Java内存模型(JMM)与并发基础

开篇:当咖啡师遇上多线程

想象一家网红咖啡店,三位咖啡师(线程)同时操作一台意式咖啡机(共享资源)。没有明确分工时可能出现:A师傅刚磨好粉,B师傅就清空了粉碗,C师傅看着空粉碗发愣。这就是并发编程的日常——JMM就是帮助咖啡师们高效协作的《吧台操作手册》。


第一章 看得见的混乱:并发问题三原罪

1.1 原子性问题:被打断的拉花教学

新手咖啡师小李正在学习心形拉花:

// 理想中的步骤
1. 倾斜咖啡杯      → 2. 注入奶泡 
3. 左右晃动        → 4. 垂直收尾

实际可能被订单打断:

// 线程切换导致步骤错乱
1. 倾斜咖啡杯      → [接单提醒弹出]3. 左右晃动 
2. 注入奶泡        → 4. 垂直收尾
// 结果得到一团抽象派奶泡

示例代码:咖啡订单计数器

class Counter {
   
    
    
    private int orders = 0;  // 总订单数
    
    // 注意:这个方法存在原子性问题
    public void addOrder() {
   
    
    
        orders++;  // 相当于三步:读值→改值→写回
    }
    
    // 正确写法应该像这样:
    // public synchronized void addOrder() { orders++; }
}
// 注释说明:
// 1. orders++ 不是原子操作,可能被线程切换打断
// 2. 当两个线程同时读取orders=5,都会改成6,实际应该到7
// 3. 这就好比两个收银员同时处理同一张订单

1.2 可见性问题:失效的价目表

假设店长更新了价目表,但:

  • 前台收银机缓存了旧价格(线程本地内存)
  • 新来的兼职生没收到通知(未刷新内存)
  • 顾客看到的价格各不相同(数据不一致)
// 价目表变量声明
boolean isPriceUpdated = false; // 无volatile修饰

// 店长线程
void updatePrice() {
   
    
    
    loadNewPrices();      // 耗时操作
    isPriceUpdated = true; // 标记已更新
}

猜你喜欢

转载自blog.csdn.net/caishuangxi111/article/details/147034228