同步机制详解
一、知识概述
在多线程环境下,多个线程同时访问共享资源可能导致数据不一致问题。Java提供了多种同步机制来保证线程安全,包括synchronized关键字、volatile变量和CAS操作。理解这些同步机制的原理和适用场景是编写正确并发程序的基础。
同步机制概览
┌─────────────────────────────────────────────────────────────────────┐
│ Java同步机制体系 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 线程安全保障 │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ 1. 互斥同步 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ synchronized│ │ Reentrant │ │ Lock │ │ │
│ │ │ 关键字 │ │ Lock │ │ 支持类 │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ 2. 非阻塞同步 │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ CAS │ │ Atomic类 │ │ │
│ │ │ 原子操作 │ │ 原子变量 │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ 3. 可见性保证 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ volatile │ │ final │ │ happens- │ │ │
│ │ │ 关键字 │ │ 字段 │ │ before │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ 4. 无同步方案 │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ ThreadLocal │ │ 不可变对象 │ │ │
│ │ │ 线程本地 │ │ (immutable)│ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
线程安全问题
/**
* 线程安全问题演示
*/
public class ThreadSafetyProblem {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 线程安全问题演示 ===\n");
// 不安全的计数器
class UnsafeCounter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
public int getCount() {
return count;
}
}
UnsafeCounter counter = new UnsafeCounter();
// 多线程并发递增
Thread[] threads = new Thread[100];
for (int i = 0; i < 100; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
}
});
}
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
System.out.println("期望结果: 100000");
System.out.println("实际结果: " + counter.getCount());
System.out.println("问题原因: count++不是原子操作");
System.out.println();
/*
count++的字节码:
1. 读取count值到操作数栈
2. 将常量1压栈
3. 执行加法
4. 将结果写回count
多线程下可能发生:
线程A读取count=0
线程B读取count=0
线程A计算count=1,写入
线程B计算count=1,写入
结果: 两次递增,但count只增加了1
*/
}
}
二、知识点详细讲解
2.1 synchronized关键字
2.1.1 基本使用
/**
* synchronized基本使用
*/
public class SynchronizedBasicDemo {
public static void main(String[] args) {
System.out.println("=== synchronized基本使用 ===\n");
synchronizedMethodDemo();
synchronizedBlockDemo();
staticSynchronizedDemo();
}
/**
* 同步方法
*/
private static void synchronizedMethodDemo() {
System.out.println("【同步方法】\n");
class Counter {
private int count = 0;
// 同步实例方法 - 锁是this对象
public synchronized void increment() {
count++;
}
// 同步实例方法
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
System.out.println("实例同步方法:");
System.out.println(" public synchronized void method() { ... }");
System.out.println(" 锁对象: this (当前实例)");
System.out.println();
}
/**
* 同步代码块
*/
private static void synchronizedBlockDemo() {
System.out.println("【同步代码块】\n");
class Counter {
private final Object lock = new Object();
private int count = 0;
public void increment() {
// 同步代码块 - 指定锁对象
synchronized (lock) {
count++;
}
}
public void incrementThis() {
// 使用this作为锁
synchronized (this) {
count++;
}
}
}
System.out.println("同步代码块:");
System.out.println(" synchronized (lockObject) { ... }");
System.out.println(" 锁对象: 括号内指定的对象");
System.out.println();
System.out.println("优点:");
System.out.println(" 1. 可以指定任意锁对象");
System.out.println(" 2. 减小锁粒度");
System.out.println(" 3. 避免锁整个方法");
System.out.println();
}
/**
* 静态同步方法
*/
private static void staticSynchronizedDemo() {
System.out.println("【静态同步方法】\n");
class StaticCounter {
private static int count = 0;
// 同步静态方法 - 锁是Class对象
public static synchronized void increment() {
count++;
}
// 等价于
public static void incrementBlock() {
synchronized (StaticCounter.class) {
count++;
}
}
}
System.out.println("静态同步方法:");
System.out.println(" public static synchronized void method() { ... }");
System.out.println(" 锁对象: Class对象 (StaticCounter.class)");
System.out.println();
System.out.println("说明:");
System.out.println(" - 静态同步方法与实例同步方法使用不同的锁");
System.out.println(" - 静态方法锁Class对象");
System.out.println(" - 实例方法锁this对象");
System.out.println(" - 两者互不影响");
System.out.println();
}
}
2.1.2 synchronized特性
/**
* synchronized特性详解
*/
public class SynchronizedFeaturesDemo {
public static void main(String[] args) {
System.out.println("=== synchronized特性 ===\n");
atomicityDemo();
reentrancyDemo();
visibilityDemo();
}
/**
* 原子性
*/
private static void atomicityDemo() {
System.out.println("【原子性】\n");
System.out.println("synchronized保证原子性:");
System.out.println(" - 同一时刻只有一个线程能进入同步块");
System.out.println(" - 代码块内的操作不会被中断");
System.out.println();
class SafeCounter {
private int count = 0;
public synchronized void increment() {
count++; // 现在是原子操作
}
public synchronized int getCount() {
return count;
}
}
System.out.println("示例: 安全的计数器");
System.out.println(" synchronized确保count++的原子性");
System.out.println();
}
/**
* 可重入性
*/
private static void reentrancyDemo() {
System.out.println("【可重入性】\n");
class ReentrantDemo {
public synchronized void methodA() {
System.out.println("methodA开始");
methodB(); // 可重入调用
System.out.println("methodA结束");
}
public synchronized void methodB() {
System.out.println("methodB执行");
}
}
System.out.println("可重入性说明:");
System.out.println(" - 同一线程可重复获取同一把锁");
System.out.println(" - 避免死锁");
System.out.println(" - 实现原理: 锁计数器");
System.out.println();
System.out.println("示例:");
System.out.println(" 线程进入methodA,获取锁,计数=1");
System.out.println(" 线程调用methodB,再次获取锁,计数=2");
System.out.println(" 线程退出methodB,释放锁,计数=1");
System.out.println(" 线程退出methodA,释放锁,计数=0");
System.out.println();
System.out.println("可重入场景:");
System.out.println(" 1. 同步方法调用同步方法");
System.out.println(" 2. 子类同步方法调用父类同步方法");
System.out.println();
}
/**
* 可见性
*/
private static void visibilityDemo() {
System.out.println("【可见性】\n");
System.out.println("synchronized保证可见性:");
System.out.println(" - 获取锁: 清空工作内存,从主内存读取");
System.out.println(" - 释放锁: 将工作内存写入主内存");
System.out.println();
System.out.println("happens-before关系:");
System.out.println(" - 释放锁 happens-before 获取锁");
System.out.println(" - 前一个线程的修改对后一个线程可见");
System.out.println();
}
}
2.1.3 synchronized原理
/**
* synchronized底层原理
*/
public class SynchronizedPrincipleDemo {
public static void main(String[] args) {
System.out.println("=== synchronized底层原理 ===\n");
monitorDemo();
objectHeaderDemo();
lockUpgradeDemo();
}
/**
* Monitor机制
*/
private static void monitorDemo() {
System.out.println("【Monitor机制】\n");
/*
每个Java对象都有一个Monitor(监视器锁)
Monitor结构:
┌─────────────────────────────────────┐
│ Monitor │
├─────────────────────────────────────┤
│ _owner: 当前持有锁的线程 │
│ _EntryList: 等待获取锁的线程队列 │
│ _WaitSet: 调用wait()的线程队列 │
│ _count: 锁计数器 │
└─────────────────────────────────────┘
同步代码块的字节码:
monitorenter // 获取Monitor
... // 同步代码
monitorexit // 释放Monitor
*/
System.out.println("Monitor工作流程:");
System.out.println();
System.out.println("1. 线程执行monitorenter:");
System.out.println(" - 如果Monitor的_owner为空,线程获取锁");
System.out.println(" - 如果_owner是当前线程,_count加1(重入)");
System.out.println(" - 否则线程进入_EntryList等待");
System.out.println();
System.out.println("2. 线程执行monitorexit:");
System.out.println(" - _count减1");
System.out.println(" - 如果_count为0,释放锁,_owner置空");
System.out.println(" - 从_EntryList唤醒一个线程");
System.out.println();
System.out.println("3. 执行wait():");
System.out.println(" - 线程释放锁");
System.out.println(" - 线程进入_WaitSet");
System.out.println();
System.out.println("4. 执行notify():");
System.out.println(" - 从_WaitSet移动一个线程到_EntryList");
System.out.println(" - 等待获取锁");
System.out.println();
}
/**
* 对象头与Mark Word
*/
private static void objectHeaderDemo() {
System.out.println("【对象头与Mark Word】\n");
/*
Java对象内存布局:
┌─────────────────────────────────────┐
│ 对象头 │
│ ┌───────────────────────────────┐ │
│ │ Mark Word (8字节) │ │
│ │ 存储锁状态、GC年龄、哈希码 │ │
│ └───────────────────────────────┘ │
│ ┌───────────────────────────────┐ │
│ │ 类型指针 (4/8字节) │ │
│ │ 指向类元数据 │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ 实例数据 │
├─────────────────────────────────────┤
│ 对齐填充 │
└─────────────────────────────────────┘
Mark Word结构 (64位JVM):
┌────────────────────────────────────────────────────────┐
│ 锁状态 │ 内容 │
├────────────────────────────────────────────────────────┤
│ 无锁 │ hashcode | age | 0 | 01 │
│ 偏向锁 │ thread ID | age | 1 | 01 │
│ 轻量级锁 │ 指向栈中Lock Record的指针 | 00 │
│ 重量级锁 │ 指向Monitor的指针 | 10 │
│ GC标记 │ 空 | 11 │
└────────────────────────────────────────────────────────┘
*/
System.out.println("Mark Word存储信息:");
System.out.println(" - 锁状态标志");
System.out.println(" - 哈希码(未锁定时)");
System.out.println(" - GC分代年龄");
System.out.println(" - 偏向锁的线程ID");
System.out.println(" - 锁记录指针/Monitor指针");
System.out.println();
}
/**
* 锁升级过程
*/
private static void lockUpgradeDemo() {
System.out.println("【锁升级过程】\n");
/*
锁升级: 偏向锁 -> 轻量级锁 -> 重量级锁
升级是单向的,不可降级
┌─────────────────────────────────────────────────────────────┐
│ 锁升级流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 无锁状态 │
│ │ │
│ ▼ │
│ ┌───────────┐ │
│ │ 偏向锁 │ 单线程重入,无竞争 │
│ │ Lock: 101 │ 在Mark Word中记录线程ID │
│ └─────┬─────┘ │
│ │ 出现竞争 │
│ ▼ │
│ ┌───────────┐ │
│ │ 轻量级锁 │ 多线程交替执行 │
│ │ Lock: 000 │ CAS将Mark Word替换为Lock Record指针 │
│ └─────┬─────┘ │
│ │ 自旋失败,竞争激烈 │
│ ▼ │
│ ┌───────────┐ │
│ │ 重量级锁 │ 多线程竞争激烈 │
│ │ Lock: 010 │ Monitor实现,线程阻塞 │
│ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
*/
System.out.println("1. 偏向锁 (Biased Lock)");
System.out.println(" - 适用: 单线程重入场景");
System.out.println(" - 原理: Mark Word记录线程ID");
System.out.println(" - 优点: 几乎无额外开销");
System.out.println(" - 撤销: 有其他线程竞争时");
System.out.println();
System.out.println("2. 轻量级锁 (Lightweight Lock)");
System.out.println(" - 适用: 多线程交替执行,竞争不激烈");
System.out.println(" - 原理: CAS操作 + 自旋");
System.out.println(" - Lock Record: 栈帧中的锁记录");
System.out.println(" - 优点: 避免线程阻塞开销");
System.out.println();
System.out.println("3. 重量级锁 (Heavyweight Lock)");
System.out.println(" - 适用: 竞争激烈");
System.out.println(" - 原理: Monitor实现");
System.out.println(" - 缺点: 线程阻塞/唤醒开销大");
System.out.println();
System.out.println("锁升级是JVM的优化,开发者无需关心");
System.out.println("相关参数:");
System.out.println(" -XX:+UseBiasedLocking 开启偏向锁(默认)");
System.out.println(" -XX:BiasedLockingStartupDelay=4000 偏向锁启动延迟");
System.out.println();
}
}
2.2 volatile关键字
2.2.1 基本概念
/**
* volatile关键字详解
*/
public class VolatileDemo {
public static void main(String[] args) {
System.out.println("=== volatile关键字 ===\n");
visibilityDemo();
orderingDemo();
atomicityLimitation();
}
/**
* 可见性保证
*/
private static void visibilityDemo() throws InterruptedException {
System.out.println("【可见性保证】\n");
class VisibilityProblem {
// 不使用volatile
boolean running = true;
void stop() {
running = false;
}
void work() {
while (running) {
// 工作循环
}
System.out.println("工作线程停止");
}
}
class VisibilitySolution {
// 使用volatile
volatile boolean running = true;
void stop() {
running = false;
}
void work() {
while (running) {
// 工作循环
}
System.out.println("工作线程停止(volatile)");
}
}
System.out.println("可见性问题:");
System.out.println(" - 线程有自己的工作内存(缓存)");
System.out.println(" - 修改可能不会立即写入主内存");
System.out.println(" - 其他线程可能看不到最新值");
System.out.println();
System.out.println("volatile解决方案:");
System.out.println(" - 写操作: 立即写入主内存");
System.out.println(" - 读操作: 从主内存读取最新值");
System.out.println(" - 保证所有线程看到最新值");
System.out.println();
System.out.println("内存屏障:");
System.out.println(" - StoreStore屏障: 禁止上面的写与下面的写重排序");
System.out.println(" - StoreLoad屏障: 禁止上面的写与下面的读重排序");
System.out.println(" - LoadLoad屏障: 禁止上面的读与下面的读重排序");
System.out.println(" - LoadStore屏障: 禁止上面的读与下面的写重排序");
System.out.println();
}
/**
* 有序性保证
*/
private static void orderingDemo() {
System.out.println("【有序性保证】\n");
/*
指令重排序示例:
初始: x = 0, y = 0
线程1: x = 1; y = 1;
线程2: r1 = y; r2 = x;
可能的执行顺序(重排序后):
线程1: y = 1; x = 1; (重排序)
线程2: r1 = y; r2 = x;
结果: r1 = 1, r2 = 0 (不符合预期)
*/
class ReorderingProblem {
int x = 0;
int y = 0;
void writer() {
x = 1;
y = 1; // 可能重排序到x=1之前
}
void reader() {
int r1 = y;
int r2 = x;
// r1 = 1, r2 = 0 是可能的
}
}
class ReorderingSolution {
volatile int x = 0;
volatile int y = 0;
void writer() {
x = 1;
y = 1; // volatile写,x=1不会被重排序到y=1之后
}
void reader() {
int r1 = y; // volatile读
int r2 = x; // 不会被重排序到y读之前
}
}
System.out.println("指令重排序:");
System.out.println(" - 编译器优化重排序");
System.out.println(" - CPU指令级并行重排序");
System.out.println(" - 内存系统重排序");
System.out.println();
System.out.println("volatile禁止重排序:");
System.out.println(" - volatile写之前的操作不会重排序到之后");
System.out.println(" - volatile读之后的操作不会重排序到之前");
System.out.println();
System.out.println("应用场景 - 双重检查锁单例:");
System.out.println(" private volatile static Singleton instance;");
System.out.println(" volatile防止对象初始化重排序");
System.out.println();
}
/**
* 原子性限制
*/
private static void atomicityLimitation() {
System.out.println("【原子性限制】\n");
class VolatileCounter {
private volatile int count = 0;
public void increment() {
count++; // 仍然不是原子操作!
}
public int getCount() {
return count;
}
}
System.out.println("⚠️ volatile不保证原子性");
System.out.println();
System.out.println("count++分析:");
System.out.println(" 1. 读取count值 (volatile读,读主内存)");
System.out.println(" 2. 加1");
System.out.println(" 3. 写入count值 (volatile写,写主内存)");
System.out.println();
System.out.println("多线程问题:");
System.out.println(" 线程A: 读取count=0");
System.out.println(" 线程B: 读取count=0");
System.out.println(" 线程A: 加1,写入count=1");
System.out.println(" 线程B: 加1,写入count=1");
System.out.println(" 结果: 两次递增,count=1");
System.out.println();
System.out.println("volatile适用场景:");
System.out.println(" ✅ 状态标志位");
System.out.println(" ✅ 一次性安全发布");
System.out.println(" ✅ 独立观察");
System.out.println(" ✅ 开销较低的读-写锁策略");
System.out.println();
System.out.println("volatile不适用场景:");
System.out.println(" ❌ 计数器(需要原子性)");
System.out.println(" ❌ 依赖当前值的更新");
System.out.println(" ❌ 复合操作");
System.out.println();
}
}
2.2.2 volatile应用场景
/**
* volatile应用场景示例
*/
public class VolatileUseCasesDemo {
public static void main(String[] args) {
System.out.println("=== volatile应用场景 ===\n");
statusFlagDemo();
doubleCheckedLocking();
cheapReadWriteLock();
}
/**
* 状态标志位
*/
private static void statusFlagDemo() {
System.out.println("【状态标志位】\n");
class Worker implements Runnable {
private volatile boolean running = true;
@Override
public void run() {
while (running) {
// 执行任务
}
System.out.println("Worker停止");
}
public void shutdown() {
running = false;
}
}
System.out.println("适用场景:");
System.out.println(" - 线程停止标志");
System.out.println(" - 状态切换开关");
System.out.println(" - 初始化完成标志");
System.out.println();
System.out.println("示例:");
System.out.println(" private volatile boolean initialized = false;");
System.out.println(" private volatile boolean shutdown = false;");
System.out.println();
}
/**
* 双重检查锁单例
*/
private static void doubleCheckedLocking() {
System.out.println("【双重检查锁单例】\n");
class Singleton {
// volatile防止指令重排序
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
System.out.println("为什么要用volatile?");
System.out.println();
System.out.println("instance = new Singleton() 分三步:");
System.out.println(" 1. 分配内存空间");
System.out.println(" 2. 初始化对象");
System.out.println(" 3. 将引用指向内存");
System.out.println();
System.out.println("重排序问题:");
System.out.println(" 可能重排序为: 1 -> 3 -> 2");
System.out.println(" 其他线程看到instance != null但对象未初始化");
System.out.println();
System.out.println("volatile解决:");
System.out.println(" volatile禁止 2 和 3 重排序");
System.out.println(" 保证对象完全初始化后才对其他线程可见");
System.out.println();
}
/**
* 开销较低的读-写锁
*/
private static void cheapReadWriteLock() {
System.out.println("【开销较低的读-写锁】\n");
class CheapReadWriteLock<T> {
private volatile T value;
public T getValue() {
return value; // volatile读,无锁
}
public synchronized void setValue(T value) {
this.value = value; // volatile写 + synchronized
}
}
System.out.println("模式:");
System.out.println(" 读: 直接读volatile变量(无锁,高吞吐)");
System.out.println(" 写: synchronized保证原子性 + volatile保证可见性");
System.out.println();
System.out.println("适用场景:");
System.out.println(" - 读多写少");
System.out.println(" - 写操作需要原子性");
System.out.println(" - 读操作不需要最新值");
System.out.println();
System.out.println("示例:");
System.out.println(" class Config {");
System.out.println(" private volatile String config;");
System.out.println(" public String getConfig() { return config; }");
System.out.println(" public synchronized void setConfig(String c) { config = c; }");
System.out.println(" }");
System.out.println();
}
}
2.3 CAS操作
2.3.1 CAS原理
import java.util.concurrent.atomic.*;
/**
* CAS (Compare-And-Swap) 操作详解
*/
public class CASDemo {
public static void main(String[] args) {
System.out.println("=== CAS操作详解 ===\n");
casPrinciple();
casInJava();
casProblem();
}
/**
* CAS原理
*/
private static void casPrinciple() {
System.out.println("【CAS原理】\n");
/*
CAS (Compare-And-Swap):
伪代码:
boolean cas(int *addr, int expected, int new_value) {
if (*addr == expected) {
*addr = new_value;
return true;
}
return false;
}
特点:
1. 原子性: 整个操作是原子的
2. 无锁: 不需要获取锁
3. 硬件支持: CPU指令级别的原子操作
*/
System.out.println("CAS三个操作数:");
System.out.println(" V (Value): 内存值");
System.out.println(" E (Expected): 预期值");
System.out.println(" N (New): 新值");
System.out.println();
System.out.println("CAS执行过程:");
System.out.println(" 如果 V == E,则 V = N,返回成功");
System.out.println(" 如果 V != E,则不做任何操作,返回失败");
System.out.println();
System.out.println("CPU指令支持:");
System.out.println(" x86: CMPXCHG指令");
System.out.println(" ARM: LDXR/STXR指令");
System.out.println();
System.out.println("JVM实现:");
System.out.println(" Unsafe类的compareAndSwapXxx方法");
System.out.println(" native方法,调用底层硬件指令");
System.out.println();
}
/**
* Java中的CAS
*/
private static void casInJava() {
System.out.println("【Java中的CAS】\n");
// AtomicInteger示例
AtomicInteger atomicInt = new AtomicInteger(0);
// CAS操作
boolean success = atomicInt.compareAndSet(0, 1);
System.out.println("CAS(0, 1) 成功: " + success);
System.out.println("当前值: " + atomicInt.get());
success = atomicInt.compareAndSet(0, 2);
System.out.println("CAS(0, 2) 成功: " + success);
System.out.println("当前值: " + atomicInt.get());
System.out.println();
System.out.println("Atomic类:");
System.out.println(" AtomicInteger");
System.out.println(" AtomicLong");
System.out.println(" AtomicBoolean");
System.out.println(" AtomicReference<V>");
System.out.println(" AtomicIntegerArray");
System.out.println(" AtomicLongArray");
System.out.println(" AtomicReferenceArray<V>");
System.out.println(" AtomicIntegerFieldUpdater<T>");
System.out.println(" AtomicLongFieldUpdater<T>");
System.out.println(" AtomicReferenceFieldUpdater<T,V>");
System.out.println(" AtomicStampedReference<V>");
System.out.println(" AtomicMarkableReference<V>");
System.out.println();
System.out.println("常用方法:");
System.out.println(" compareAndSet(expected, new) CAS操作");
System.out.println(" getAndIncrement() 原子递增并返回旧值");
System.out.println(" incrementAndGet() 原子递增并返回新值");
System.out.println(" getAndAdd(delta) 原子增加并返回旧值");
System.out.println(" addAndGet(delta) 原子增加并返回新值");
System.out.println();
// 模拟CAS实现
simulateCAS();
}
/**
* 模拟CAS实现
*/
private static void simulateCAS() {
System.out.println("【模拟CAS实现】\n");
class SimulatedCAS {
private int value;
public SimulatedCAS(int value) {
this.value = value;
}
// 模拟CAS操作(实际需要硬件支持)
public synchronized boolean compareAndSwap(int expected, int newValue) {
if (value == expected) {
value = newValue;
return true;
}
return false;
}
public int get() {
return value;
}
}
class CASCounter {
private SimulatedCAS cas = new SimulatedCAS(0);
public void increment() {
int oldValue;
int newValue;
do {
oldValue = cas.get();
newValue = oldValue + 1;
} while (!cas.compareAndSwap(oldValue, newValue));
}
public int get() {
return cas.get();
}
}
System.out.println("CAS实现计数器:");
System.out.println(" do {");
System.out.println(" old = cas.get();");
System.out.println(" new = old + 1;");
System.out.println(" } while (!cas.compareAndSwap(old, new));");
System.out.println();
System.out.println("说明:");
System.out.println(" - 循环尝试直到成功");
System.out.println(" - 无锁设计");
System.out.println(" - 适合低竞争场景");
System.out.println();
}
/**
* CAS问题
*/
private static void casProblem() {
System.out.println("【CAS的问题】\n");
System.out.println("1. ABA问题");
System.out.println(" 场景:");
System.out.println(" 线程1读取V=A");
System.out.println(" 线程2将V改为B,再改回A");
System.out.println(" 线程1执行CAS(A, C),成功");
System.out.println(" 问题: V实际上被修改过");
System.out.println();
System.out.println(" 解决方案: AtomicStampedReference");
AtomicStampedReference<Integer> stampedRef =
new AtomicStampedReference<>(100, 0);
int[] stampHolder = new int[1];
Integer ref = stampedRef.get(stampHolder);
System.out.println(" 值: " + ref + ", 版本: " + stampHolder[0]);
stampedRef.compareAndSet(100, 101, stampHolder[0], stampHolder[0] + 1);
System.out.println();
System.out.println("2. 自旋开销");
System.out.println(" 问题: 高竞争时CAS失败率高,导致大量自旋");
System.out.println(" 解决: 使用自适应自旋或退化为锁");
System.out.println();
System.out.println("3. 只能保证一个变量的原子性");
System.out.println(" 问题: 无法同时对多个变量进行CAS操作");
System.out.println(" 解决: 将多个变量封装为一个对象");
System.out.println(" 使用AtomicReference");
System.out.println();
}
}
2.3.2 Atomic类详解
import java.util.concurrent.atomic.*;
import java.util.function.*;
/**
* Atomic类详解
*/
public class AtomicClassesDemo {
public static void main(String[] args) {
System.out.println("=== Atomic类详解 ===\n");
basicAtomicDemo();
atomicReferenceDemo();
atomicFieldUpdaterDemo();
atomicPerformanceDemo();
}
/**
* 基本Atomic类
*/
private static void basicAtomicDemo() {
System.out.println("【基本Atomic类】\n");
// AtomicInteger
AtomicInteger atomicInt = new AtomicInteger(0);
// 基本操作
atomicInt.set(10);
System.out.println("set(10): " + atomicInt.get());
atomicInt.lazySet(20); // 延迟设置,性能更好但不保证立即可见
System.out.println("lazySet(20): " + atomicInt.get());
// 原子更新
System.out.println("getAndIncrement(): " + atomicInt.getAndIncrement()); // 返回20
System.out.println("incrementAndGet(): " + atomicInt.incrementAndGet()); // 返回22
System.out.println("getAndAdd(10): " + atomicInt.getAndAdd(10)); // 返回22
System.out.println("addAndGet(10): " + atomicInt.addAndGet(10)); // 返回42
// 条件更新
System.out.println("compareAndSet(42, 50): " + atomicInt.compareAndSet(42, 50));
System.out.println("当前值: " + atomicInt.get());
// 函数式更新
int result = atomicInt.updateAndGet(x -> x * 2);
System.out.println("updateAndGet(x -> x * 2): " + result);
result = atomicInt.accumulateAndGet(10, (x, y) -> x + y);
System.out.println("accumulateAndGet(10, (x,y)->x+y): " + result);
System.out.println();
}
/**
* AtomicReference
*/
private static void atomicReferenceDemo() {
System.out.println("【AtomicReference】\n");
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
AtomicReference<User> userRef = new AtomicReference<>(new User("张三", 20));
System.out.println("初始用户: " + userRef.get());
User oldUser = userRef.get();
User newUser = new User("李四", 25);
boolean success = userRef.compareAndSet(oldUser, newUser);
System.out.println("CAS更新: " + success);
System.out.println("当前用户: " + userRef.get());
// 原子更新
userRef.updateAndGet(u -> new User(u.name, u.age + 1));
System.out.println("年龄+1: " + userRef.get());
System.out.println();
// AtomicStampedReference解决ABA问题
System.out.println("【AtomicStampedReference】\n");
AtomicStampedReference<Integer> stampedRef =
new AtomicStampedReference<>(100, 0);
int[] stamp = new int[1];
Integer value = stampedRef.get(stamp);
System.out.println("值: " + value + ", 版本: " + stamp[0]);
// 尝试更新
boolean updated = stampedRef.compareAndSet(100, 101, stamp[0], stamp[0] + 1);
System.out.println("更新成功: " + updated);
value = stampedRef.get(stamp);
System.out.println("值: " + value + ", 版本: " + stamp[0]);
// 使用旧版本更新(会失败)
updated = stampedRef.compareAndSet(101, 102, 0, 1);
System.out.println("使用旧版本更新成功: " + updated);
System.out.println();
}
/**
* AtomicIntegerFieldUpdater
*/
private static void atomicFieldUpdaterDemo() {
System.out.println("【AtomicIntegerFieldUpdater】\n");
class Person {
volatile String name;
volatile int age; // 必须是volatile
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// 创建字段更新器
AtomicIntegerFieldUpdater<Person> ageUpdater =
AtomicIntegerFieldUpdater.newUpdater(Person.class, "age");
Person person = new Person("王五", 30);
System.out.println("初始年龄: " + person.age);
ageUpdater.incrementAndGet(person);
System.out.println("incrementAndGet: " + person.age);
ageUpdater.compareAndSet(person, 31, 35);
System.out.println("CAS更新后: " + person.age);
System.out.println();
System.out.println("使用场景:");
System.out.println(" - 已有类无法修改,需要对字段进行原子操作");
System.out.println(" - 节省内存(不需要创建Atomic对象)");
System.out.println();
System.out.println("要求:");
System.out.println(" - 字段必须是volatile");
System.out.println(" - 字段必须可访问");
System.out.println(" - 只能是int/long类型");
System.out.println();
}
/**
* Atomic性能对比
*/
private static void atomicPerformanceDemo() throws InterruptedException {
System.out.println("【Atomic性能对比】\n");
// synchronized vs AtomicInteger
class SyncCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
int threadCount = 10;
int incrementsPerThread = 1000000;
// synchronized测试
SyncCounter syncCounter = new SyncCounter();
long start = System.currentTimeMillis();
Thread[] syncThreads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
syncThreads[i] = new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
syncCounter.increment();
}
});
}
for (Thread t : syncThreads) t.start();
for (Thread t : syncThreads) t.join();
long syncTime = System.currentTimeMillis() - start;
System.out.println("synchronized: " + syncTime + "ms, 结果: " + syncCounter.getCount());
// AtomicInteger测试
AtomicInteger atomicCounter = new AtomicInteger(0);
start = System.currentTimeMillis();
Thread[] atomicThreads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
atomicThreads[i] = new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
atomicCounter.incrementAndGet();
}
});
}
for (Thread t : atomicThreads) t.start();
for (Thread t : atomicThreads) t.join();
long atomicTime = System.currentTimeMillis() - start;
System.out.println("AtomicInteger: " + atomicTime + "ms, 结果: " + atomicCounter.get());
// LongAdder测试(高并发更优)
LongAdder longAdder = new LongAdder();
start = System.currentTimeMillis();
Thread[] adderThreads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
adderThreads[i] = new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
longAdder.increment();
}
});
}
for (Thread t : adderThreads) t.start();
for (Thread t : adderThreads) t.join();
long adderTime = System.currentTimeMillis() - start;
System.out.println("LongAdder: " + adderTime + "ms, 结果: " + longAdder.sum());
System.out.println();
System.out.println("结论:");
System.out.println(" - 低竞争: AtomicInteger性能较好");
System.out.println(" - 高竞争: LongAdder性能更优");
System.out.println(" - LongAdder使用分段累加,减少竞争");
System.out.println();
}
}
三、可运行Java代码示例
完整示例:线程安全计数器对比
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/**
* 线程安全计数器完整示例
*/
public class ThreadSafeCounterDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 线程安全计数器对比 ===\n");
// 1. 不安全的计数器
testCounter("不安全计数器", new UnsafeCounter());
// 2. synchronized计数器
testCounter("synchronized计数器", new SynchronizedCounter());
// 3. ReentrantLock计数器
testCounter("ReentrantLock计数器", new LockCounter());
// 4. AtomicInteger计数器
testCounter("AtomicInteger计数器", new AtomicCounter());
// 5. LongAdder计数器
testCounter("LongAdder计数器", new LongAdderCounter());
// 6. 无锁CAS计数器
testCounter("CAS计数器", new CASCounter());
}
interface Counter {
void increment();
int getCount();
}
static void testCounter(String name, Counter counter) throws InterruptedException {
int threadCount = 10;
int incrementsPerThread = 100000;
CountDownLatch latch = new CountDownLatch(threadCount);
long start = System.currentTimeMillis();
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
counter.increment();
}
latch.countDown();
}).start();
}
latch.await();
long elapsed = System.currentTimeMillis() - start;
int expected = threadCount * incrementsPerThread;
int actual = counter.getCount();
boolean correct = (expected == actual);
System.out.printf("%-25s 耗时: %4dms, 结果: %7d/%7d %s%n",
name, elapsed, actual, expected, correct ? "✅" : "❌");
}
// 不安全的计数器
static class UnsafeCounter implements Counter {
private int count = 0;
@Override
public void increment() {
count++;
}
@Override
public int getCount() {
return count;
}
}
// synchronized计数器
static class SynchronizedCounter implements Counter {
private int count = 0;
@Override
public synchronized void increment() {
count++;
}
@Override
public synchronized int getCount() {
return count;
}
}
// ReentrantLock计数器
static class LockCounter implements Counter {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
@Override
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
// AtomicInteger计数器
static class AtomicCounter implements Counter {
private AtomicInteger count = new AtomicInteger(0);
@Override
public void increment() {
count.incrementAndGet();
}
@Override
public int getCount() {
return count.get();
}
}
// LongAdder计数器
static class LongAdderCounter implements Counter {
private LongAdder count = new LongAdder();
@Override
public void increment() {
count.increment();
}
@Override
public int getCount() {
return count.intValue();
}
}
// CAS计数器
static class CASCounter implements Counter {
private AtomicInteger count = new AtomicInteger(0);
@Override
public void increment() {
int oldVal, newVal;
do {
oldVal = count.get();
newVal = oldVal + 1;
} while (!count.compareAndSet(oldVal, newVal));
}
@Override
public int getCount() {
return count.get();
}
}
}
四、总结与最佳实践
核心要点回顾
| 机制 | 特性 | 适用场景 |
|---|---|---|
| synchronized | 互斥性、可见性、可重入 | 复合操作、需要原子性 |
| volatile | 可见性、有序性 | 状态标志、单例双重检查 |
| CAS | 原子性、无锁 | 计数器、低竞争场景 |
最佳实践
-
选择正确的同步机制
- 复合操作用synchronized或Lock
- 状态标志用volatile
- 计数器用Atomic或LongAdder
-
避免过度同步
- 同步块尽量短
- 避免在同步块中调用外部方法
-
正确使用volatile
- 只用于状态标志
- 不用于依赖当前值的更新
-
理解锁升级
- JVM自动优化
- 关注竞争程度
相关JVM参数
# 偏向锁
-XX:+UseBiasedLocking # 开启偏向锁(默认)
-XX:BiasedLockingStartupDelay=0 # 偏向锁启动延迟
# 自旋锁
-XX:+UseSpinning # 开启自旋(默认)
-XX:SpinWaitIterations=10 # 自旋次数
# 逃逸分析
-XX:+DoEscapeAnalysis # 开启逃逸分析(默认)
扩展阅读
- 《Java并发编程实战》:同步机制章节
- 《深入理解Java虚拟机》:锁优化章节
- JSR-133:Java内存模型规范