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

线程安全与同步机制:从synchronized到Lock的演进

引子:一个购物车的线程安全之路 在上一篇文章中,我们理解了并发编程的三大核心问题:可见性、原子性、有序性。现在我们要解决这个问题:如何让多线程安全地访问共享数据? 场景:电商购物车的并发问题 /** * 购物车服务(线程不安全版本) * 问题:多个线程同时添加商品,可能导致数据丢失 */ public class ShoppingCart { private Map<String, Integer> items = new HashMap<>(); // 商品ID → 数量 // 添加商品到购物车 public void addItem(String productId, int quantity) { Integer currentQty = items.get(productId); if (currentQty == null) { items.put(productId, quantity); } else { items.put(productId, currentQty + quantity); } } // 获取购物车总商品数 public int getTotalItems() { int total = 0; for (Integer qty : items.values()) { total += qty; } return total; } } // 并发测试 public class CartTest { public static void main(String[] args) throws InterruptedException { ShoppingCart cart = new ShoppingCart(); // 10个线程并发添加商品 Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { threads[i] = new Thread(() -> { for (int j = 0; j < 100; j++) { cart.addItem("product-123", 1); } }); } for (Thread t : threads) t.start(); for (Thread t : threads) t.join(); System.out.println("期望数量:1000"); System.out.println("实际数量:" + cart.getTotalItems()); } } /* 执行结果(多次运行不一致): 第1次:实际数量:856 ❌ 丢失144次更新 第2次:实际数量:923 ❌ 丢失77次更新 第3次:实际数量:891 ❌ 丢失109次更新 问题分析: 1. HashMap本身不是线程安全的 2. addItem方法不是原子操作(读取、计算、写入三步) 3. 多线程并发执行导致数据竞争 解决方案演进: Level 1:使用synchronized → 简单但粗粒度 Level 2:使用ReentrantLock → 灵活但需要手动管理 Level 3:使用ConcurrentHashMap → 高性能(下一篇讲解) */ 本文将深入探讨如何通过synchronized和Lock来保证线程安全。 ...

2025-11-03 · maneng

如约数科科技工作室

浙ICP备2025203501号

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