Java 乐观锁
核心概念
悲观锁
- 假设最坏情况,每次访问共享资源时都会有其他线程来修改数据。
- 访问之前会先加锁,确保同一时刻只有一个线程操作数据。
- 代表实现:synchronized、Lock、数据库中的行锁、表锁。
乐观锁
- 假设大多数情况没有冲突,允许多个线程同时访问数据。
- 访问共享资源时不会加锁,而是判断数据是否被其他线程修改过。
- 若数据被修改,则重新获取数据,直到数据未被修改再执行操作。
- 实现方式:CAS(Compare And Swap)、版本号机制。
Java 中乐观锁的代表类
- AtomicInteger
- AtomicLong
- AtomicReference
- AtomicStampedReference
- AtomicMarkableReference
- 等等
代码实现示例
package com.optimisticlock;
import sun.misc.Unsafe;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 悲观锁:假设最坏情况,每次访问共享资源时都会有其他线程来修改数据,因此在访问之前会先加锁,确保同一时刻只有一个线程操作数据
* synchronized
* Lock
* 数据库中的行锁、表锁
* 乐观锁:假设大多数情况没有冲突,允许多个线程同时访问数据,每次访问共享资源时,不会加锁,而是判断数据是否被其他线程修改过,如果被修改过,则重新获取数据,直到没有被修改过
* CAS(Compare And Swap)
* 版本号机制
* java中乐观锁的代表:
* AtomicInteger
* AtomicLong
* AtomicReference
* AtomicStampedReference
* AtomicMarkableReference
* 等等
* @author Jing61
*/
public class OptimisticLock {
// volatile修饰的变量,会保证可见性,不会被JVM指令重排序
private volatile int value;
private static final Unsafe U = Unsafe.getUnsafe();
// 内存中的偏移量
private static final long VALUE;
static {
try {
VALUE = U.objectFieldOffset(OptimisticLock.class.getDeclaredField("value"));
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
public static void main(String[] args) {
// 1.利用 CAS
OptimisticLock optimisticLock = new OptimisticLock();
// 获取当前值
int expected = optimisticLock.value;
while (!U.compareAndSwapInt(optimisticLock, VALUE, expected, expected + 1)) {
expected = optimisticLock.value;
}
// 2. AtomicInteger
AtomicInteger atomicInteger = new AtomicInteger();
// getAndIncrement()方法是使得当前值增加1,如果当前值被修改过,则会重新获取当前值,直到没有被修改过
System.out.println(atomicInteger.getAndIncrement());
}
}
补充说明
- volatile 关键字作用:保证变量的可见性,禁止JVM对指令进行重排序,确保多线程环境下变量值的更新能被及时感知。
- Unsafe 类:提供底层CAS操作支持,通过
objectFieldOffset获取变量在对象中的内存偏移量,用于直接操作内存数据。
- Atomic 系列类优势:无需手动编写CAS循环逻辑,底层已封装安全高效的乐观锁实现,简化多线程并发编程。