Java并发编程锁:从原理到高效应用
## 目录
1. [并发编程与锁的基础概念](#1-并发编程与锁的基础概念)
2. [为什么需要锁](#2-为什么需要锁)
3. [锁的原理深度解析](#3-锁的原理深度解析)
4. [Java锁的完整分类](#4-java锁的完整分类)
5. [场景一:互斥访问场景](#5-场景一互斥访问场景)
6. [场景二:可见性保证场景](#6-场景二可见性保证场景)
7. [场景三:顺序性保证场景](#7-场景三顺序性保证场景)
8. [场景四:读写分离场景](#8-场景四读写分离场景)
9. [场景五:分布式场景](#9-场景五分布式场景)
10. [锁的性能优化策略](#10-锁的性能优化策略)
11. [锁的最佳实践](#11-锁的最佳实践)
12. [总结与选择指南](#12-总结与选择指南)
---
## 1. 并发编程与锁的基础概念
### 1.1 并发编程的三大问题
```java
/**
* 并发编程的三大问题
*/
public class ConcurrencyProblems {
/**
* 问题1:原子性问题
*
* 定义:一个操作或多个操作要么全部执行且执行的过程不会被任何因素打断,
* 要么就都不执行。
*
* 示例:count++ 操作不是原子的
*/
public static class AtomicityProblem {
private int count = 0;
// count++ 实际上包含三个操作:
// 1. 读取count的值
// 2. 将count的值加1
// 3. 将新值写回count
// 在多线程环境下,这三个操作可能被打断
public void increment() {
count++; // 不是原子操作
}
}
/**
* 问题2:可见性问题
*
* 定义:当一个线程修改了共享变量的值,其他线程能够立即看到修改后的值。
*
* 示例:线程A修改了变量,线程B可能看不到
*/
public static class VisibilityProblem {
private boolean flag = false;
// 线程A执行
public void writer() {
flag = true; // 线程A修改了flag
}
// 线程B执行
public void reader() {
while (!flag) { // 线程B可能永远看不到flag的变化
// 死循环
}
}
}
/**
* 问题3:有序性问题
*
* 定义:指令执行的顺序按照代码的先后顺序执行。
*
* 示例:指令重排序
*/
public static class OrderingProblem {
private int x = 0;
private boolean flag = false;
// 线程A执行
public void writer() {
x = 42; // 1
flag = true; // 2
// 由于指令重排序,2可能在1之前执行
}
// 线程B执行
public void reader() {
if (flag) { // 3
// 由于重排序,可能看到flag=true但x=0
System.out.println(x); // 可能输出0,而不是42
}
}
}
}
```
### 1.2 JMM(Java内存模型)
```java
/**
* Java内存模型
*/
public class JavaMemoryModel {
/*
* JMM抽象结构:
*
* ┌──────────────┐
* │ 线程A │
* │ (工作内存) │
* └──────┬───────┘
* │
* └──────┬────────────────────┐
* │ │
* ┌──────────────▼───────┐ ┌───────▼─────────────┐
* │ 主内存 │ │ 主内存 │
* │ (共享变量) │ │ (共享变量) │
* └──────────────┬───────┘ └───────┬─────────────┘
* │ │
* ┌──────┴────────────────────┘
* │
* ┌──────▼───────┐
* │ 线程B │
* │ (工作内存) │
* └──────────────┘
*
* 工作内存:线程私有的内存区域
* 主内存:所有线程共享的内存区域
*
* JMM规定:
* 1. 所有的变量都存储在主内存中
* 2. 每个线程都有自己的工作内存,保存了该线程使用到的变量的副本
* 3. 线程对变量的所有操作都必须在工作内存中进行
* 4. 不同线程之间无法直接访问对方工作内存中的变量
* 5. 线程间变量的传递需要通过主内存来完成
*/
}
```
### 1.3 volatile关键字
```java
/**
* volatile关键字详解
*/
public class VolatileKeyword {
/**
* volatile的特性:
* 1. 保证可见性:当一个线程修改了volatile变量,其他线程能够立即看到
* 2. 禁止指令重排序:禁止JVM和处理器对volatile变量的操作进行重排序
* 3. 不保证原子性:volatile不能保证复合操作的原子性
*/
private volatile boolean flag = false;
// 示例1:保证可见性
public void visibilityExample() {
// 线程A
new Thread(() -> {
flag = true;
}).start();
// 线程B
new Thread(() -> {
while (!flag) {
// 由于volatile保证可见性,线程B能够立即看到flag的变化
}
System.out.println("flag is true");
}).start();
}
// 示例2:禁止指令重排序(单例模式的双重检查锁定)
private static volatile VolatileKeyword instance;
public static VolatileKeyword getInstance() {
if (instance == null) {
synchronized (VolatileKeyword.class) {
if (instance == null) {
// 由于volatile禁止重排序,保证了instance的初始化完成
// 才会对instance赋值
instance = new VolatileKeyword();
}
}
}
return instance;
}
// 示例3:不保证原子性
private volatile int count = 0;
public void atomicityExample() {
// 即使使用volatile,count++仍然不是原子操作
// 多线程环境下仍然会出现问题
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
count++; // 不是原子操作
}
}).start();
}
// 最终结果可能小于10000
System.out.println("count = " + count);
}
}
```
---
## 2. 为什么需要锁
### 2.1 竞态条件(Race Condition)
```java
/**
* 竞态条件示例
*/
public class RaceCondition {
private int count = 0;
/**
* 问题代码:多线程环境下count++可能出错
*/
public void increment() {
// count++ 的三个步骤:
// 1. 读取count的值到寄存器
// 2. 将寄存器的值加1
// 3. 将新值写回count
//
// 假设count的初始值为0
// 线程A执行步骤1:读取count=0
// 线程B执行步骤1:读取count=0
// 线程A执行步骤2:count=1
// 线程B执行步骤2:count=1
// 线程A执行步骤3:写回count=1
// 线程B执行步骤3:写回count=1
// 结果:count=1,而不是2
count++;
}
/**
* 使用synchronized解决竞态条件
*/
public synchronized void incrementSafe() {
count++;
}
/**
* 使用ReentrantLock解决竞态条件
*/
private final ReentrantLock lock = new ReentrantLock();
public void incrementSafeWithLock() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
/**
* 测试竞态条件
*/
public static void main(String[] args) throws InterruptedException {
RaceCondition raceCondition = new RaceCondition();
// 创建100个线程,每个线程增加1000次
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
raceCondition.increment();
}
}).start();
}
Thread.sleep(1000);
System.out.println("最终结果(可能小于100000):" + raceCondition.count);
}
}
```
### 2.2 死锁(Deadlock)
```java
/**
* 死锁示例
*/
public class DeadlockExample {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
/**
* 死锁场景:两个线程互相等待对方持有的锁
*/
public static void deadlockDemo() {
// 线程1:先获取lock1,再获取lock2
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("线程1获取lock1");
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1等待lock2");
synchronized (lock2) {
System.out.println("线程1获取lock2");
}
}
});
// 线程2:先获取lock2,再获取lock1
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("线程2获取lock2");
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2等待lock1");
synchronized (lock1) {
System.out.println("线程2获取lock1");
}
}
});
thread1.start();
thread2.start();
// 两个线程都会阻塞,程序永远无法结束
}
/**
* 解决死锁:按顺序获取锁
*/
public static void avoidDeadlock() {
// 两个线程都按照相同的顺序获取锁
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("线程1获取lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("线程1获取lock2");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock1) { // 先获取lock1,而不是lock2
System.out.println("线程2获取lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("线程2获取lock2");
}
}
});
thread1.start();
thread2.start();
}
}
```
---
## 3. 锁的原理深度解析
### 3.1 synchronized原理
```java
/**
* synchronized原理深度解析
*/
public class SynchronizedPrinciple {
/**
* synchronized的三种使用方式:
* 1. 实例方法锁:锁住当前实例对象
* 2. 静态方法锁:锁住Class对象
* 3. 代码块锁:锁住指定对象
*/
/**
* 1. 实例方法锁
* 锁住的是this对象
*/
public synchronized void instanceMethodLock() {
// 同一时刻只有一个线程可以执行该方法
}
/**
* 2. 静态方法锁
* 锁住的是SynchronizedPrinciple.class对象
*/
public static synchronized void staticMethodLock() {
// 同一时刻只有一个线程可以执行该方法
}
/**
* 3. 代码块锁
* 锁住的是lock对象
*/
private final Object lock = new Object();
public void blockLock() {
synchronized (lock) {
// 同一时刻只有一个线程可以执行该代码块
}
}
}
/**
* synchronized的字节码分析
*/
public class SynchronizedBytecode {
private int count = 0;
public synchronized void increment() {
count++;
}
/**
* 上述方法编译后的字节码(简化):
*
* public synchronized void increment();
* Code:
* 0: aload_0
* 1: dup
* 2: getfield #2 // Field count:I
* 5: iconst_1
* 6: iadd
* 7: putfield #2 // Field count:I
* 10: return
*
* 注意:synchronized方法的字节码中没有monitorenter和monitorexit指令
* 而是通过方法常量池中的ACC_SYNCHRONIZED标志来隐式实现
*
* synchronized代码块的字节码:
*
* public void incrementBlock();
* Code:
* 0: aload_0
* 1: getfield #2 // Field lock:Ljava/lang/Object;
* 4: dup
* 5: astore_1
* 6: monitorenter // 获取锁
* 7: aload_0
* 8: dup
* 9: getfield #3 // Field count:I
* 12: iconst_1
* 13: iadd
* 14: putfield #3 // Field count:I
* 17: aload_1
* 18: monitorexit // 释放锁
* 19: goto 25
* 22: aload_1
* 23: monitorexit // 异常时释放锁
* 24: athrow
* 25: return
* Exception table:
* from to target type
* 7 19 22 any
* 22 24 22 any
*/
}
```
### 3.2 Monitor(对象监视器)
```java
/**
* Monitor(对象监视器)详解
*/
public class MonitorDetail {
/*
* Monitor结构:
*
* 每个Java对象都有一个Monitor,Monitor包含:
*
* ┌─────────────────────────────────────────┐
* │ Owner(持有者) │
* │ 持有Monitor的线程 │
* ├─────────────────────────────────────────┤
* │ EntryList(入口列表) │
* │ 等待获取Monitor的线程队列 │
* ├─────────────────────────────────────────┤
* │ WaitSet(等待集合) │
* │ 调用wait()方法的线程队列 │
* └─────────────────────────────────────────┘
*
* Monitor工作流程:
* 1. 线程尝试获取Monitor
* 2. 如果Monitor的Owner为null,当前线程成为Owner
* 3. 如果Monitor的Owner不为null,当前线程进入EntryList
* 4. Owner线程执行完代码后释放Monitor
* 5. EntryList中的一个线程被唤醒成为Owner
*
* wait()和notify():
* - wait():线程释放Monitor并进入WaitSet
* - notify():唤醒WaitSet中的一个线程
* - notifyAll():唤醒WaitSet中的所有线程
*/
}
```
### 3.3 锁升级过程
```java
/**
* 锁升级过程
*/
public class LockUpgrade {
/*
* 锁的四种状态(级别从低到高):
* 1. 无锁(No Lock)
* 2. 偏向锁(Biased Lock)
* 3. 轻量级锁(Lightweight Lock)
* 4. 重量级锁(Heavyweight Lock)
*
* 锁只能升级不能降级(但在JDK6之后,偏向锁可以被撤销)
*
* 锁升级过程:
*
* ┌─────────────┐
* │ 无锁 │
* └──────┬──────┘
* │ 第一次访问
* ▼
* ┌─────────────┐ 有其他线程竞争
* │ 偏向锁 │ ─────────────┐
* └──────┬──────┘ │
* │ │
* │ 撤销偏向锁 │
* ▼ │
* ┌─────────────┐ │
* │ 轻量级锁 │ ─────────────┘
* └──────┬──────┘ CAS失败多次
* │
* │ 竞争激烈
* ▼
* ┌─────────────┐
* │ 重量级锁 │
* └─────────────┘
*
* 1. 偏向锁(Biased Lock)
* - 场景:只有一个线程访问同步块
* - 原理:在对象头中记录线程ID,该线程后续访问无需加锁
* - 性能:接近无锁性能
*
* 2. 轻量级锁(Lightweight Lock)
* - 场景:多个线程交替访问同步块,没有竞争
* - 原理:使用CAS自旋尝试获取锁
* - 性能:比重量级锁快,但比偏向锁慢
*
* 3. 重量级锁(Heavyweight Lock)
* - 场景:多个线程同时竞争锁
* - 原理:使用操作系统的Mutex Lock,线程会阻塞
* - 性能:最慢,但最可靠
*/
}
```
### 3.4 对象头结构
```java
/**
* 对象头结构(Mark Word)
*/
public class ObjectHeader {
/*
* Mark Word结构(64位JVM):
*
* ┌─────────────────────────────────────────────────────────────┐
* │ unused:25 │ identity_hashcode:31 │ unused:1 │ age:4 │ biased_lock:1 │ lock:2 │
* └─────────────────────────────────────────────────────────────┘
*
* lock的值表示锁的状态:
* - 00:轻量级锁
* - 01:无锁或偏向锁(根据biased_lock判断)
* - 10:重量级锁
* - 11:GC标记
*
* 不同锁状态下的Mark Word:
*
* ┌────────────┬─────────────────────────────────────────────────────┐
* │ 锁状态 │ Mark Word (64 bits) │
* ├────────────┼─────────────────────────────────────────────────────┤
* │ 无锁 │ unused:25 │ identity_hashcode:31 │ unused:1 │ age:4 │
* │ │ biased_lock:0 │ lock:01 │
* ├────────────┼─────────────────────────────────────────────────────┤
* │ 偏向锁 │ thread:54 │ epoch:2 │ unused:1 │ age:4 │ │
* │ │ biased_lock:1 │ lock:01 │
* ├────────────┼─────────────────────────────────────────────────────┤
* │ 轻量级锁 │ ptr_to_lock_record:62 │
* │ │ lock:00 │
* ├────────────┼─────────────────────────────────────────────────────┤
* │ 重量级锁 │ ptr_to_heavyweight_monitor:62 │
* │ │ lock:10 │
* ├────────────┼─────────────────────────────────────────────────────┤
* │ GC标记 │ 11111111 │
* └────────────┴─────────────────────────────────────────────────────┘
*/
}
```
---
## 4. Java锁的完整分类
### 4.1 锁的分类体系
```java
/**
* Java锁的完整分类
*/
public class LockClassification {
/*
* 锁的分类体系:
*
* ┌─────────────────────────────────────────────────────────┐
* │ Java锁 │
* ├──────────────┬──────────────────────────────────────────┤
* │ synchronized│ Lock接口 │
* ├──────────────┼──────────────────────────────────────────┤
* │ │ ReentrantLock(可重入锁) │
* │ ├──────────────────────────────────────────┤
* │ │ ReentrantReadWriteLock(读写锁) │
* │ ├──────────────────────────────────────────┤
* │ │ StampedLock(印章锁) │
* │ ├──────────────────────────────────────────┤
* │ │ Condition(条件变量) │
* └──────────────┴──────────────────────────────────────────┘
*
* 按特性分类:
*
* 1. 可重入锁 vs 不可重入锁
* 2. 公平锁 vs 非公平锁
* 3. 悲观锁 vs 乐观锁
* 4. 独占锁 vs 共享锁
* 5. 自旋锁 vs 非自旋锁
* 6. 分段锁 vs 全局锁
* 7. 偏向锁 vs 轻量级锁 vs 重量级锁
*/
}
```
### 4.2 synchronized vs Lock
```java
/**
* synchronized vs Lock 对比
*/
public class SynchronizedVsLock {
private final Lock lock = new ReentrantLock();
/**
* synchronized方式
*/
public void synchronizedMethod() {
synchronized (this) {
// 临界区代码
}
}
/**
* Lock方式
*/
public void lockMethod() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
/**
* 对比分析
*/
public static void comparison() {
System.out.println("┌─────────────────────────────────────────────────────────────────┐");
System.out.println("│ 对比项 │ synchronized │ Lock │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 实现方式 │ JVM层面实现 │ JDK API实现 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 释放锁 │ 自动释放 │ 手动释放 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 可中断性 │ 不可中断 │ 可中断(lockInterruptibly)│");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 公平性 │ 非公平 │ 可选择公平/非公平 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 条件变量 │ wait/notify │ Condition │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 性能 │ JDK6后优化明显 │ 性能稳定 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 使用复杂度 │ 简单 │ 较复杂 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 支持读写锁 │ 不支持 │ 支持(ReentrantReadWriteLock)│");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 获取锁状态 │ 不支持 │ 支持 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 尝试获取锁 │ 不支持 │ 支持(tryLock) │");
System.out.println("└─────────────────────────────────────────────────────────────────┘");
}
}
```
### 4.3 ReentrantLock详解
```java
/**
* ReentrantLock详解
*/
public class ReentrantLockDetail {
private final Lock lock = new ReentrantLock();
/**
* 基本使用
*/
public void basicUsage() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock(); // 必须在finally中释放锁
}
}
/**
* 可中断锁
*/
private final Lock lockInterruptibly = new ReentrantLock();
public void interruptibleLock() throws InterruptedException {
lockInterruptibly.lockInterruptibly(); // 可被中断
try {
// 临界区代码
} finally {
lockInterruptibly.unlock();
}
}
/**
* 尝试获取锁
*/
public void tryLock() {
if (lock.tryLock()) { // 尝试获取锁,立即返回
try {
// 获取锁成功,执行临界区代码
} finally {
lock.unlock();
}
} else {
// 获取锁失败,执行其他逻辑
System.out.println("获取锁失败");
}
}
/**
* 带超时的尝试获取锁
*/
public void tryLockWithTimeout() throws InterruptedException {
if (lock.tryLock(1, TimeUnit.SECONDS)) { // 等待1秒
try {
// 获取锁成功,执行临界区代码
} finally {
lock.unlock();
}
} else {
// 获取锁超时
System.out.println("获取锁超时");
}
}
/**
* 公平锁
*/
private final Lock fairLock = new ReentrantLock(true); // 公平锁
public void fairLockExample() {
fairLock.lock();
try {
// 临界区代码
} finally {
fairLock.unlock();
}
}
/**
* 检查锁状态
*/
public void checkLockStatus() {
ReentrantLock reentrantLock = (ReentrantLock) lock;
// 检查是否持有锁
boolean isLocked = reentrantLock.isLocked();
// 检查当前线程是否持有锁
boolean isHeldByCurrentThread = reentrantLock.isHeldByCurrentThread();
// 获取重入次数
int holdCount = reentrantLock.getHoldCount();
// 检查是否是公平锁
boolean isFair = reentrantLock.isFair();
// 获取等待队列长度
int queueLength = reentrantLock.getQueueLength();
System.out.println("isLocked: " + isLocked);
System.out.println("isHeldByCurrentThread: " + isHeldByCurrentThread);
System.out.println("holdCount: " + holdCount);
System.out.println("isFair: " + isFair);
System.out.println("queueLength: " + queueLength);
}
/**
* 可重入性示例
*/
public void reentrantExample() {
lock.lock();
try {
System.out.println("第一次获取锁");
// 重入锁
lock.lock();
try {
System.out.println("第二次获取锁(重入)");
// 再次重入
lock.lock();
try {
System.out.println("第三次获取锁(重入)");
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
}
}
```
### 4.4 ReentrantReadWriteLock详解
```java
/**
* ReentrantReadWriteLock详解
*/
public class ReentrantReadWriteLockDetail {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private Map cache = new HashMap<>();
/**
* 读操作
*/
public String get(String key) {
readLock.lock(); // 获取读锁
try {
return cache.get(key);
} finally {
readLock.unlock(); // 释放读锁
}
}
/**
* 写操作
*/
public void put(String key, String value) {
writeLock.lock(); // 获取写锁
try {
cache.put(key, value);
} finally {
writeLock.unlock(); // 释放写锁
}
}
/**
* 锁降级:从写锁降级为读锁
*/
public void lockDowngrade() {
writeLock.lock();
try {
// 获取写锁
System.out.println("获取写锁");
// 降级为读锁
readLock.lock();
try {
System.out.println("降级为读锁");
// 可以继续读取数据
} finally {
writeLock.unlock(); // 释放写锁
}
// 继续持有读锁
System.out.println("继续持有读锁");
} finally {
readLock.unlock(); // 释放读锁
}
}
/**
* 注意:不支持锁升级(从读锁升级为写锁)
*/
public void lockUpgrade() {
readLock.lock();
try {
// 获取读锁
System.out.println("获取读锁");
// 尝试升级为写锁(会死锁)
writeLock.lock();
try {
System.out.println("升级为写锁");
} finally {
writeLock.unlock();
}
} finally {
readLock.unlock();
}
}
/**
* 检查锁状态
*/
public void checkLockStatus() {
// 获取读锁的持有数
int readLockCount = rwLock.getReadLockCount();
// 检查是否有线程持有写锁
boolean isWriteLocked = rwLock.isWriteLocked();
// 检查当前线程是否持有写锁
boolean isHeldByCurrentThread = rwLock.isWriteLockedByCurrentThread();
// 获取写锁的重入次数
int writeHoldCount = rwLock.getWriteHoldCount();
System.out.println("readLockCount: " + readLockCount);
System.out.println("isWriteLocked: " + isWriteLocked);
System.out.println("isHeldByCurrentThread: " + isHeldByCurrentThread);
System.out.println("writeHoldCount: " + writeHoldCount);
}
}
```
### 4.5 StampedLock详解
```java
/**
* StampedLock详解
*/
public class StampedLockDetail {
private final StampedLock stampedLock = new StampedLock();
private double x, y;
/**
* 读操作(乐观读)
*/
public double distanceFromOrigin() {
// 获取乐观读锁
long stamp = stampedLock.tryOptimisticRead();
// 读取数据(不加锁)
double currentX = x;
double currentY = y;
// 验证乐观读锁是否有效
if (!stampedLock.validate(stamp)) {
// 乐观读锁失效,升级为悲观读锁
stamp = stampedLock.readLock();
try {
currentX = x;
currentY = y;
} finally {
stampedLock.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
/**
* 写操作
*/
public void move(double deltaX, double deltaY) {
// 获取写锁
long stamp = stampedLock.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
stampedLock.unlockWrite(stamp);
}
}
/**
* 读操作(悲观读)
*/
public void readPessimistic() {
// 获取悲观读锁
long stamp = stampedLock.readLock();
try {
// 读取数据
System.out.println("x = " + x + ", y = " + y);
} finally {
stampedLock.unlockRead(stamp);
}
}
/**
* 读写锁的转换
*/
public void moveIfAtOrigin(double newX, double newY) {
// 获取乐观读锁
long stamp = stampedLock.tryOptimisticRead();
// 检查是否在原点
if (x == 0.0 && y == 0.0) {
// 验证乐观读锁
if (!stampedLock.validate(stamp)) {
// 乐观读锁失效,获取读锁
stamp = stampedLock.readLock();
try {
if (x == 0.0 && y == 0.0) {
// 尝试转换为写锁
long ws = stampedLock.tryConvertToWriteLock(stamp);
if (ws != 0L) {
stamp = ws; // 转换成功
x = newX;
y = newY;
} else {
// 转换失败,获取写锁
stampedLock.unlockRead(stamp);
stamp = stampedLock.writeLock();
try {
x = newX;
y = newY;
} finally {
stampedLock.unlockWrite(stamp);
}
return;
}
}
} finally {
stampedLock.unlock(stamp);
}
} else {
// 乐观读锁有效,直接获取写锁
stamp = stampedLock.writeLock();
try {
x = newX;
y = newY;
} finally {
stampedLock.unlockWrite(stamp);
}
}
}
}
}
```
---
## 5. 场景一:互斥访问场景
### 5.1 场景描述
**场景特征**:
- 多个线程需要同时访问共享资源
- 同一时刻只允许一个线程访问
- 需要保证数据的完整性和一致性
**典型应用**:
- 计数器
- 银行账户转账
- 库存扣减
- 订单创建
### 5.2 锁的选择
```java
/**
* 场景一:互斥访问场景的锁选择
*/
public class ExclusiveAccessScenario {
/**
* 方案1:使用synchronized
* 适用场景:
* - 代码结构简单
* - 不需要高级功能
* - 性能要求不是极端
*/
public static class SynchronizedSolution {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
/**
* 方案2:使用ReentrantLock
* 适用场景:
* - 需要可中断的锁
* - 需要尝试获取锁
* - 需要公平锁
* - 需要获取锁状态
*/
public static class ReentrantLockSolution {
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
/**
* 方案3:使用Atomic类(无锁)
* 适用场景:
* - 单一变量的原子操作
* - 高并发场景
* - 不需要复杂的同步逻辑
*/
public static class AtomicSolution {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
}
```
### 5.3 实际应用:银行转账
```java
/**
* 银行转账场景
*/
public class BankTransfer {
/**
* 账户类
*/
public static class Account {
private String accountId;
private double balance;
private final Object lock = new Object(); // 每个账户有自己的锁
public Account(String accountId, double balance) {
this.accountId = accountId;
this.balance = balance;
}
/**
* 转账(死锁风险)
*/
public void transferToDeadlockRisk(Account target, double amount) {
// 线程A:从账户1转账到账户2
synchronized (this) {
System.out.println("线程A锁定账户1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (target) {
System.out.println("线程A等待账户2");
// 转账逻辑
this.balance -= amount;
target.balance += amount;
}
}
// 线程B:从账户2转账到账户1
// 可能发生死锁
}
/**
* 转账(避免死锁:按顺序获取锁)
*/
public void transferToSafe(Account target, double amount) {
// 按照账户ID的顺序获取锁
Account first = this.accountId.compareTo(target.accountId) < 0 ? this : target;
Account second = this.accountId.compareTo(target.accountId) < 0 ? target : this;
synchronized (first) {
synchronized (second) {
// 转账逻辑
this.balance -= amount;
target.balance += amount;
}
}
}
/**
* 转账(使用ReentrantLock避免死锁)
*/
public void transferToWithReentrantLock(Account target, double amount) {
// 按照账户ID的顺序获取锁
Account first = this.accountId.compareTo(target.accountId) < 0 ? this : target;
Account second = this.accountId.compareTo(target.accountId) < 0 ? target : this;
first.lock.lock();
try {
second.lock.lock();
try {
// 转账逻辑
this.balance -= amount;
target.balance += amount;
} finally {
second.lock.unlock();
}
} finally {
first.lock.unlock();
}
}
public double getBalance() {
return balance;
}
}
}
```
---
## 6. 场景二:可见性保证场景
### 6.1 场景描述
**场景特征**:
- 多个线程需要看到最新的共享变量值
- 一个线程修改了变量,其他线程需要立即看到
- 不需要互斥访问,只需要可见性
**典型应用**:
- 状态标志
- 配置更新
- 发布-订阅模式
### 6.2 锁的选择
```java
/**
* 场景二:可见性保证场景的锁选择
*/
public class VisibilityScenario {
/**
* 方案1:使用volatile
* 适用场景:
* - 单个变量的读写
* - 保证可见性
* - 不保证原子性
*/
public static class VolatileSolution {
private volatile boolean flag = false;
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean getFlag() {
return flag;
}
}
/**
* 方案2:使用Atomic类
* 适用场景:
* - 需要原子操作
* - 需要CAS操作
*/
public static class AtomicSolution {
private final AtomicInteger flag = new AtomicInteger(0);
public void setFlag(int flag) {
this.flag.set(flag);
}
public int getFlag() {
return flag.get();
}
public boolean compareAndSet(int expect, int update) {
return flag.compareAndSet(expect, update);
}
}
/**
* 方案3:使用synchronized
* 适用场景:
* - 需要保证可见性
* - 同时需要保证原子性
*/
public static class SynchronizedSolution {
private boolean flag = false;
public synchronized void setFlag(boolean flag) {
this.flag = flag;
}
public synchronized boolean getFlag() {
return flag;
}
}
}
```
### 6.3 实际应用:配置更新
```java
/**
* 配置更新场景
*/
public class ConfigUpdate {
/**
* 配置类
*/
public static class Config {
private volatile String config;
private volatile int version;
public void updateConfig(String newConfig) {
// 使用volatile保证可见性
this.config = newConfig;
this.version++;
}
public String getConfig() {
return config;
}
public int getVersion() {
return version;
}
}
/**
* 配置管理器
*/
public static class ConfigManager {
private volatile Config currentConfig;
private final Object lock = new Object();
/**
* 更新配置(需要保证原子性)
*/
public void updateConfig(String newConfig) {
synchronized (lock) {
Config newConfigObj = new Config();
newConfigObj.updateConfig(newConfig);
currentConfig = newConfigObj;
}
}
/**
* 获取配置(只需要可见性)
*/
public Config getConfig() {
return currentConfig;
}
}
/**
* 配置监听器
*/
public static class ConfigListener implements Runnable {
private volatile boolean running = true;
private ConfigManager configManager;
public ConfigListener(ConfigManager configManager) {
this.configManager = configManager;
}
public void stop() {
running = false;
}
@Override
public void run() {
Config lastConfig = null;
while (running) {
Config currentConfig = configManager.getConfig();
// 使用volatile保证可见性,能够立即看到配置更新
if (currentConfig != null &&
(lastConfig == null || currentConfig.getVersion() != lastConfig.getVersion())) {
System.out.println("配置更新: " + currentConfig.getConfig());
lastConfig = currentConfig;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
```
---
## 7. 场景三:顺序性保证场景
### 7.1 场景描述
**场景特征**:
- 需要保证操作的执行顺序
- 防止指令重排序
- 保证happens-before关系
**典型应用**:
- 单例模式
- 双重检查锁定
- 初始化顺序
### 7.2 锁的选择
```java
/**
* 场景三:顺序性保证场景的锁选择
*/
public class OrderingScenario {
/**
* 方案1:使用volatile禁止指令重排序
* 适用场景:
* - 单例模式
* - 需要禁止指令重排序
*/
public static class VolatileSolution {
private volatile static VolatileSolution instance;
public static VolatileSolution getInstance() {
if (instance == null) {
synchronized (VolatileSolution.class) {
if (instance == null) {
// volatile禁止重排序,保证了instance的初始化完成
// 才会对instance赋值
instance = new VolatileSolution();
}
}
}
return instance;
}
}
/**
* 方案2:使用synchronized
* 适用场景:
* - 需要保证操作的顺序
* - 需要保证happens-before关系
*/
public static class SynchronizedSolution {
private static SynchronizedSolution instance;
public static synchronized SynchronizedSolution getInstance() {
if (instance == null) {
instance = new SynchronizedSolution();
}
return instance;
}
}
}
```
### 7.3 实际应用:双重检查锁定
```java
/**
* 双重检查锁定示例
*/
public class DoubleCheckedLocking {
/**
* 单例实现
*/
public static class Singleton {
private volatile static Singleton instance;
private Singleton() {
// 私有构造函数
}
/**
* 双重检查锁定
*/
public static Singleton getInstance() {
// 第一次检查(不加锁)
if (instance == null) {
// 加锁
synchronized (Singleton.class) {
// 第二次检查(加锁后)
if (instance == null) {
// volatile禁止重排序,保证了instance的初始化完成
// 才会对instance赋值
instance = new Singleton();
}
}
}
return instance;
}
}
/**
* 为什么需要volatile?
*
* instance = new Singleton() 包含三个步骤:
* 1. 分配内存
* 2. 初始化对象
* 3. 将instance指向分配的内存
*
* 如果没有volatile,可能会发生重排序:
* 1. 分配内存
* 3. 将instance指向分配的内存
* 2. 初始化对象
*
* 这样可能导致其他线程看到一个未初始化的对象
*/
}
```
---
## 8. 场景四:读写分离场景
### 8.1 场景描述
**场景特征**:
- 读操作远多于写操作
- 多个线程可以同时读
- 写操作需要独占访问
- 读操作不需要互斥
**典型应用**:
- 缓存系统
- 配置中心
- 数据访问层
### 8.2 锁的选择
```java
/**
* 场景四:读写分离场景的锁选择
*/
public class ReadWriteScenario {
/**
* 方案1:使用ReentrantReadWriteLock
* 适用场景:
* - 读多写少
* - 读写分离
* - 读操作不需要互斥
*/
public static class ReadWriteLockSolution {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private Map cache = new HashMap<>();
public String get(String key) {
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}
/**
* 方案2:使用StampedLock
* 适用场景:
* - 读多写少
* - 更高性能
* - 乐观读
*/
public static class StampedLockSolution {
private final StampedLock stampedLock = new StampedLock();
private Map cache = new HashMap<>();
public String get(String key) {
// 乐观读
long stamp = stampedLock.tryOptimisticRead();
String value = cache.get(key);
// 验证乐观读锁是否有效
if (!stampedLock.validate(stamp)) {
// 乐观读锁失效,升级为悲观读锁
stamp = stampedLock.readLock();
try {
value = cache.get(key);
} finally {
stampedLock.unlockRead(stamp);
}
}
return value;
}
public void put(String key, String value) {
long stamp = stampedLock.writeLock();
try {
cache.put(key, value);
} finally {
stampedLock.unlockWrite(stamp);
}
}
}
}
```
### 8.3 实际应用:缓存系统
```java
/**
* 缓存系统实现
*/
public class CacheSystem {
/**
* 基于ReentrantReadWriteLock的缓存
*/
public static class ReadWriteLockCache {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private final Map cache = new HashMap<>();
private final Map expireTime = new HashMap<>();
/**
* 获取缓存
*/
public V get(K key) {
readLock.lock();
try {
// 检查是否过期
Long expire = expireTime.get(key);
if (expire != null && System.currentTimeMillis() > expire) {
return null;
}
return cache.get(key);
} finally {
readLock.unlock();
}
}
/**
* 设置缓存
*/
public void put(K key, V value, long ttl) {
writeLock.lock();
try {
cache.put(key, value);
expireTime.put(key, System.currentTimeMillis() + ttl);
} finally {
writeLock.unlock();
}
}
/**
* 删除缓存
*/
public void remove(K key) {
writeLock.lock();
try {
cache.remove(key);
expireTime.remove(key);
} finally {
writeLock.unlock();
}
}
/**
* 清空缓存
*/
public void clear() {
writeLock.lock();
try {
cache.clear();
expireTime.clear();
} finally {
writeLock.unlock();
}
}
}
/**
* 基于StampedLock的缓存(更高性能)
*/
public static class StampedLockCache {
private final StampedLock stampedLock = new StampedLock();
private final Map cache = new HashMap<>();
private final Map expireTime = new HashMap<>();
/**
* 获取缓存(乐观读)
*/
public V get(K key) {
// 乐观读
long stamp = stampedLock.tryOptimisticRead();
V value = cache.get(key);
// 验证乐观读锁是否有效
if (!stampedLock.validate(stamp)) {
// 乐观读锁失效,升级为悲观读锁
stamp = stampedLock.readLock();
try {
// 检查是否过期
Long expire = expireTime.get(key);
if (expire != null && System.currentTimeMillis() > expire) {
return null;
}
value = cache.get(key);
} finally {
stampedLock.unlockRead(stamp);
}
} else {
// 乐观读锁有效,检查是否过期
Long expire = expireTime.get(key);
if (expire != null && System.currentTimeMillis() > expire) {
return null;
}
}
return value;
}
/**
* 设置缓存
*/
public void put(K key, V value, long ttl) {
long stamp = stampedLock.writeLock();
try {
cache.put(key, value);
expireTime.put(key, System.currentTimeMillis() + ttl);
} finally {
stampedLock.unlockWrite(stamp);
}
}
}
}
```
---
## 9. 场景五:分布式场景
### 9.1 场景描述
**场景特征**:
- 跨进程、跨服务器的并发控制
- 需要保证分布式环境下的互斥访问
- 需要防止分布式死锁
**典型应用**:
- 分布式任务调度
- 分布式限流
- 分布式事务
### 9.2 锁的选择
```java
/**
* 场景五:分布式场景的锁选择
*/
public class DistributedScenario {
/**
* 方案1:基于Redis的分布式锁
* 适用场景:
* - Redis环境
* - 中等并发
* - 需要分布式锁
*/
public static class RedisDistributedLock {
private final Jedis jedis;
private final String lockKey;
private final String requestId;
private final int expireTime;
public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.requestId = UUID.randomUUID().toString();
this.expireTime = expireTime;
}
/**
* 获取锁
*/
public boolean tryLock() {
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
return "OK".equals(result);
}
/**
* 释放锁
*/
public boolean unlock() {
String luaScript =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
Object result = jedis.eval(luaScript, Collections.singletonList(lockKey),
Collections.singletonList(requestId));
return "1".equals(result.toString());
}
}
/**
* 方案2:基于ZooKeeper的分布式锁
* 适用场景:
* - ZooKeeper环境
* - 高可靠性要求
* - 需要分布式锁
*/
public static class ZookeeperDistributedLock {
private final ZooKeeper zk;
private final String lockPath;
private String currentPath;
public ZookeeperDistributedLock(ZooKeeper zk, String lockPath) {
this.zk = zk;
this.lockPath = lockPath;
}
/**
* 获取锁
*/
public boolean tryLock() throws Exception {
// 创建临时顺序节点
currentPath = zk.create(lockPath + "/lock-", new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
// 获取所有子节点
List children = zk.getChildren(lockPath, false);
Collections.sort(children);
// 判断当前节点是否是最小的
String smallestNode = children.get(0);
if (currentPath.endsWith(smallestNode)) {
return true; // 获取锁成功
}
// 获取前一个节点
int currentIndex = children.indexOf(currentPath.substring(lockPath.length() + 1));
String previousNode = children.get(currentIndex - 1);
// 监听前一个节点
final CountDownLatch latch = new CountDownLatch(1);
zk.exists(lockPath + "/" + previousNode, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted) {
latch.countDown();
}
}
});
// 等待前一个节点删除
latch.await();
return true;
}
/**
* 释放锁
*/
public void unlock() throws Exception {
if (currentPath != null) {
zk.delete(currentPath, -1);
}
}
}
}
```
### 9.3 实际应用:分布式限流
```java
/**
* 分布式限流实现
*/
public class DistributedRateLimiter {
/**
* 基于Redis的分布式限流
*/
public static class RedisRateLimiter {
private final Jedis jedis;
private final String key;
private final int limit;
private final int windowSize;
public RedisRateLimiter(Jedis jedis, String key, int limit, int windowSize) {
this.jedis = jedis;
this.key = key;
this.limit = limit;
this.windowSize = windowSize;
}
/**
* 尝试获取令牌
*/
public boolean tryAcquire() {
String luaScript =
"local current = redis.call('incr', KEYS[1]) " +
"if current == 1 then " +
" redis.call('expire', KEYS[1], ARGV[1]) " +
"end " +
"if current <= tonumber(ARGV[2]) then " +
" return 1 " +
"else " +
" return 0 " +
"end";
Object result = jedis.eval(luaScript,
Collections.singletonList(key),
Arrays.asList(String.valueOf(windowSize),
String.valueOf(limit)));
return "1".equals(result.toString());
}
}
/**
* 基于ZooKeeper的分布式限流
*/
public static class ZookeeperRateLimiter {
private final ZooKeeper zk;
private final String path;
private final int limit;
public ZookeeperRateLimiter(ZooKeeper zk, String path, int limit) {
this.zk = zk;
this.path = path;
this.limit = limit;
}
/**
* 尝试获取令牌
*/
public boolean tryAcquire() throws Exception {
// 获取当前时间窗口
long currentTime = System.currentTimeMillis();
long windowStart = currentTime / 1000 * 1000;
String windowPath = path + "/" + windowStart;
// 检查时间窗口是否存在
if (zk.exists(windowPath, false) == null) {
try {
zk.create(windowPath, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
} catch (KeeperException.NodeExistsException e) {
// 节点已存在,忽略
}
}
// 获取当前请求数
List children = zk.getChildren(windowPath, false);
if (children.size() < limit) {
// 创建请求节点
zk.create(windowPath + "/request-", new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
return true;
}
return false;
}
}
}
```
---
## 10. 锁的性能优化策略
### 10.1 减少锁的持有时间
```java
/**
* 减少锁的持有时间
*/
public class ReduceLockHoldTime {
private final Lock lock = new ReentrantLock();
private List list = new ArrayList<>();
/**
* 错误示例:锁的持有时间过长
*/
public void badExample() {
lock.lock();
try {
// 在锁内执行耗时的IO操作
String data = readFromFile(); // 耗时操作
list.add(data);
// 在锁内执行耗时的计算
String result = expensiveCalculation(data); // 耗时操作
list.add(result);
} finally {
lock.unlock();
}
}
/**
* 正确示例:减少锁的持有时间
*/
public void goodExample() {
// 在锁外执行耗时的IO操作
String data = readFromFile();
// 在锁外执行耗时的计算
String result = expensiveCalculation(data);
// 只在需要加锁的时候加锁
lock.lock();
try {
list.add(data);
list.add(result);
} finally {
lock.unlock();
}
}
private String readFromFile() {
// 模拟文件读取
return "data";
}
private String expensiveCalculation(String data) {
// 模拟耗时计算
return data.toUpperCase();
}
}
```
### 10.2 减小锁的粒度
```java
/**
* 减小锁的粒度
*/
public class ReduceLockGranularity {
/**
* 错误示例:锁的粒度过大
*/
public static class BadExample {
private final Lock lock = new ReentrantLock();
private List list1 = new ArrayList<>();
private List list2 = new ArrayList<>();
public void addToList1(String data) {
lock.lock();
try {
list1.add(data);
} finally {
lock.unlock();
}
}
public void addToList2(String data) {
lock.lock();
try {
list2.add(data);
} finally {
lock.unlock();
}
}
}
/**
* 正确示例:减小锁的粒度
*/
public static class GoodExample {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
private List list1 = new ArrayList<>();
private List list2 = new ArrayList<>();
public void addToList1(String data) {
lock1.lock();
try {
list1.add(data);
} finally {
lock1.unlock();
}
}
public void addToList2(String data) {
lock2.lock();
try {
list2.add(data);
} finally {
lock2.unlock();
}
}
}
/**
* 更好的方案:使用ConcurrentHashMap
*/
public static class BestExample {
private final ConcurrentHashMap map1 = new ConcurrentHashMap<>();
private final ConcurrentHashMap map2 = new ConcurrentHashMap<>();
public void addToMap1(String key, String value) {
map1.put(key, value);
}
public void addToMap2(String key, String value) {
map2.put(key, value);
}
}
}
```
### 10.3 使用读写锁
```java
/**
* 使用读写锁提高并发性能
*/
public class UseReadWriteLock {
/**
* 使用synchronized(读操作也会互斥)
*/
public static class SynchronizedVersion {
private final Map cache = new HashMap<>();
public synchronized String get(String key) {
return cache.get(key);
}
public synchronized void put(String key, String value) {
cache.put(key, value);
}
}
/**
* 使用ReentrantReadWriteLock(读操作可以并发)
*/
public static class ReadWriteLockVersion {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private final Map cache = new HashMap<>();
public String get(String key) {
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}
}
```
### 10.4 使用乐观锁
```java
/**
* 使用乐观锁提高并发性能
*/
public class UseOptimisticLock {
/**
* 悲观锁:每次访问都加锁
*/
public static class PessimisticLock {
private final Lock lock = new ReentrantLock();
private int version = 0;
public void update() {
lock.lock();
try {
version++;
} finally {
lock.unlock();
}
}
}
/**
* 乐观锁:使用CAS更新
*/
public static class OptimisticLock {
private final AtomicInteger version = new AtomicInteger(0);
public void update() {
// CAS更新,无需加锁
version.incrementAndGet();
}
public boolean compareAndSet(int expect, int update) {
return version.compareAndSet(expect, update);
}
}
}
```
### 10.5 使用锁分离技术
```java
/**
* 使用锁分离技术
*/
public class LockStriping {
/**
* 锁分离示例
*/
public static class StripedMap {
private static final int STRIPE_COUNT = 16;
private final Lock[] locks = new Lock[STRIPE_COUNT];
private final Map[] maps = new Map[STRIPE_COUNT];
@SuppressWarnings("unchecked")
public StripedMap() {
for (int i = 0; i < STRIPE_COUNT; i++) {
locks[i] = new ReentrantLock();
maps[i] = new HashMap<>();
}
}
/**
* 根据key的哈希值选择对应的锁
*/
private int getStripeIndex(K key) {
return Math.abs(key.hashCode() % STRIPE_COUNT);
}
public void put(K key, V value) {
int index = getStripeIndex(key);
locks[index].lock();
try {
maps[index].put(key, value);
} finally {
locks[index].unlock();
}
}
public V get(K key) {
int index = getStripeIndex(key);
locks[index].lock();
try {
return maps[index].get(key);
} finally {
locks[index].unlock();
}
}
}
}
```
---
## 11. 锁的最佳实践
### 11.1 锁的使用原则
```java
/**
* 锁的使用原则
*/
public class LockPrinciples {
/**
* 原则1:锁的获取和释放必须成对出现
*/
public void principle1() {
Lock lock = new ReentrantLock();
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock(); // 必须在finally中释放锁
}
}
/**
* 原则2:避免在锁内执行耗时操作
*/
public void principle2() {
Lock lock = new ReentrantLock();
// 在锁外执行耗时操作
String data = fetchData();
lock.lock();
try {
// 只在必要时加锁
processData(data);
} finally {
lock.unlock();
}
}
/**
* 原则3:锁的顺序要一致,避免死锁
*/
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void principle3() {
// 按照固定的顺序获取锁
synchronized (lock1) {
synchronized (lock2) {
// 临界区代码
}
}
}
/**
* 原则4:尽量减小锁的粒度
*/
public void principle4() {
// 使用多个细粒度的锁,而不是一个大锁
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
lock1.lock();
try {
// 操作1
} finally {
lock1.unlock();
}
lock2.lock();
try {
// 操作2
} finally {
lock2.unlock();
}
}
/**
* 原则5:优先使用内置锁synchronized
*/
public void principle5() {
// 优先使用synchronized,简单可靠
synchronized (this) {
// 临界区代码
}
}
/**
* 原则6:避免嵌套锁
*/
public void principle6() {
Lock lock = new ReentrantLock();
lock.lock();
try {
// 不要在锁内再次获取锁
// 这样会增加死锁的风险
} finally {
lock.unlock();
}
}
private String fetchData() {
return "data";
}
private void processData(String data) {
// 处理数据
}
}
```
### 11.2 常见陷阱
```java
/**
* 锁的常见陷阱
*/
public class LockPitfalls {
/**
* 陷阱1:忘记释放锁
*/
public void pitfall1() {
Lock lock = new ReentrantLock();
lock.lock();
// 忘记释放锁
// 如果在临界区内发生异常,锁永远不会被释放
}
/**
* 陷阱2:在锁内调用外部方法
*/
public void pitfall2() {
Lock lock = new ReentrantLock();
lock.lock();
try {
externalMethod(); // 可能在锁内执行很久
} finally {
lock.unlock();
}
}
private void externalMethod() {
// 外部方法可能很耗时
}
/**
* 陷阱3:锁的粒度过大
*/
private final Object globalLock = new Object();
public void pitfall3() {
synchronized (globalLock) {
// 整个方法都在锁内,严重影响并发性能
}
}
/**
* 陷阱4:死锁
*/
private final Object lockA = new Object();
private final Object lockB = new Object();
public void pitfall4() {
// 线程1
new Thread(() -> {
synchronized (lockA) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
// 可能发生死锁
}
}
}).start();
// 线程2
new Thread(() -> {
synchronized (lockB) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA) {
// 可能发生死锁
}
}
}).start();
}
/**
* 陷阱5:使用String作为锁对象
*/
public void pitfall5() {
String lock1 = "LOCK";
String lock2 = "LOCK"; // String常量池
// lock1和lock2是同一个对象,可能导致意外锁定
synchronized (lock1) {
// 临界区
}
}
}
```
---
## 12. 总结与选择指南
### 12.1 锁的选择决策树
```java
/**
* 锁的选择决策树
*/
public class LockSelectionGuide {
/**
* 锁的选择流程:
*
* 是否需要分布式锁?
* ├─ 是 → 使用Redis分布式锁或ZooKeeper分布式锁
* └─ 否 ↓
*
* 是否需要读写分离?
* ├─ 是 → 使用ReentrantReadWriteLock或StampedLock
* └─ 否 ↓
*
* 是否需要高级功能(可中断、公平锁、尝试获取锁)?
* ├─ 是 → 使用ReentrantLock
* └─ 否 ↓
*
* 是否需要高性能(单变量操作)?
* ├─ 是 → 使用Atomic类
* └─ 否 ↓
*
* 使用synchronized
*/
}
```
### 12.2 场景与锁的映射
```java
/**
* 场景与锁的映射
*/
public class ScenarioLockMapping {
public static void main(String[] args) {
System.out.println("┌─────────────────────────────────────────────────────────────────┐");
System.out.println("│ 场景 │ 推荐锁 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 简单互斥访问 │ synchronized │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 需要可中断的锁 │ ReentrantLock.lockInterruptibly() │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 需要尝试获取锁 │ ReentrantLock.tryLock() │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 需要公平锁 │ ReentrantLock(true) │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 读多写少 │ ReentrantReadWriteLock │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 读写分离且要求高性能 │ StampedLock │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 单变量原子操作 │ AtomicInteger/AtomicLong │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 保证可见性 │ volatile │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 禁止指令重排序 │ volatile │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 分布式互斥访问 │ Redis分布式锁/ZooKeeper分布式锁 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 分布式限流 │ Redis限流/ZooKeeper限流 │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 高并发计数器 │ LongAdder/AtomicLong │");
System.out.println("├─────────────────────────────────────────────────────────────────┤");
System.out.println("│ 缓存系统 │ ConcurrentHashMap │");
System.out.println("└─────────────────────────────────────────────────────────────────┘");
}
}
```
### 12.3 性能对比
```java
/**
* 各种锁的性能对比
*/
public class LockPerformanceComparison {
/**
* 性能测试
*/
public static void performanceTest() throws InterruptedException {
int threadCount = 100;
int incrementCount = 10000;
// synchronized性能测试
long synchronizedStart = System.currentTimeMillis();
SynchronizedCounter synchronizedCounter = new SynchronizedCounter();
CountDownLatch synchronizedLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
for (int j = 0; j < incrementCount; j++) {
synchronizedCounter.increment();
}
synchronizedLatch.countDown();
}).start();
}
synchronizedLatch.await();
long synchronizedEnd = System.currentTimeMillis();
// ReentrantLock性能测试
long reentrantLockStart = System.currentTimeMillis();
ReentrantLockCounter reentrantLockCounter = new ReentrantLockCounter();
CountDownLatch reentrantLockLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
for (int j = 0; j < incrementCount; j++) {
reentrantLockCounter.increment();
}
reentrantLockLatch.countDown();
}).start();
}
reentrantLockLatch.await();
long reentrantLockEnd = System.currentTimeMillis();
// AtomicInteger性能测试
long atomicStart = System.currentTimeMillis();
AtomicCounter atomicCounter = new AtomicCounter();
CountDownLatch atomicLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
for (int j = 0; j < incrementCount; j++) {
atomicCounter.increment();
}
atomicLatch.countDown();
}).start();
}
atomicLatch.await();
long atomicEnd = System.currentTimeMillis();
// 输出结果
System.out.println("synchronized耗时: " + (synchronizedEnd - synchronizedStart) + "ms");
System.out.println("ReentrantLock耗时: " + (reentrantLockEnd - reentrantLockStart) + "ms");
System.out.println("AtomicInteger耗时: " + (atomicEnd - atomicStart) + "ms");
}
static class SynchronizedCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
}
static class ReentrantLockCounter {
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
static class AtomicCounter {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
}
}
```
### 12.4 总结
```java
/**
* 总结
*/
public class Summary {
public static void main(String[] args) {
System.out.println("【锁的核心要点】");
System.out.println("1. 识别需要锁的场景:互斥访问、可见性、顺序性");
System.out.println("2. 选择合适的锁类型:根据场景选择synchronized、ReentrantLock、ReadWriteLock等");
System.out.println("3. 高效使用锁:减少锁持有时间、减小锁粒度、使用读写锁");
System.out.println("4. 避免常见陷阱:死锁、忘记释放锁、锁粒度过大");
System.out.println();
System.out.println("【锁的选择建议】");
System.out.println("1. 优先使用synchronized:简单、可靠、性能好");
System.out.println("2. 需要高级功能时使用ReentrantLock:可中断、公平锁、尝试获取锁");
System.out.println("3. 读多写少使用ReadWriteLock:提高并发性能");
System.out.println("4. 单变量操作使用Atomic类:无锁、高性能");
System.out.println("5. 保证可见性使用volatile:轻量级、高效");
System.out.println("6. 分布式场景使用分布式锁:Redis、ZooKeeper");
System.out.println();
System.out.println("【性能优化建议】");
System.out.println("1. 减少锁的持有时间");
System.out.println("2. 减小锁的粒度");
System.out.println("3. 使用读写锁");
System.out.println("4. 使用乐观锁");
System.out.println("5. 使用锁分离技术");
System.out.println("6. 使用并发集合");
}
}
```
---
## 结语
通过本文的学习,你应该已经掌握了:
1. **并发编程的基础知识**:原子性、可见性、有序性三大问题
2. **锁的原理深度解析**:synchronized原理、Monitor、锁升级过程、对象头结构
3. **Java锁的完整分类**:synchronized、ReentrantLock、ReadWriteLock、StampedLock等
4. **五大典型场景的锁选择**:互斥访问、可见性保证、顺序性保证、读写分离、分布式场景
5. **锁的性能优化策略**:减少锁持有时间、减小锁粒度、使用读写锁等
6. **锁的最佳实践**:使用原则、常见陷阱、选择指南
锁是并发编程的核心工具,合理使用锁可以保证线程安全,提高程序性能。选择合适的锁类型,遵循最佳实践,才能编写出高效、可靠的并发程序!
建议:
1. 深入学习JVM并发机制
2. 实践更多并发编程项目
3. 学习并发集合的使用
4. 关注并发性能调优
5. 学习分布式锁的实现