当前位置:网站首页>分析一下CSDN大佬写的CAS,可重入锁, 非公平锁
分析一下CSDN大佬写的CAS,可重入锁, 非公平锁
2022-07-27 02:25:00 【打工仔呀~】
代码来源:https://blog.csdn.net/kkgbn/article/details/100136988
对其代码添加入自己理解的注释
public class MyReentrantLock {
// 用于执行低级、不安全操作的方法的集合
private static final Unsafe unsafe = getUnsafe();
// 锁柄
private Thread lockHolder;
// 此队列对元素进行 FIFO(先进先出)排序
private ConcurrentLinkedQueue<Thread> queue = new ConcurrentLinkedQueue<>();
/** * 同步状态。 */
private volatile int state;
private static final long stateOffset;
static {
try {
// 对象字段偏移
stateOffset = unsafe.objectFieldOffset(MyReentrantLock.class.getDeclaredField("state"));
} catch (Exception ex) {
throw new Error(ex);
}
}
protected final int getState() {
return state;
}
protected final void setState(int state) {
this.state = state;
}
/** * 比较并设置状态 * @param expect * @param update * @return 如果成功则为true */
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
public Thread getLockHolder() {
return lockHolder;
}
public void setLockHolder(Thread lockHolder) {
this.lockHolder = lockHolder;
}
// CAS 以及 可重入逻辑
public boolean tryAcquire() {
// 返回对当前正在执行的线程对象的引用。
final Thread current = Thread.currentThread();
// 获取状态
int c = getState();
if (c == 0) {
// 比较并设置状态
if (compareAndSetState(0, 1)) {
// 传入当前执行的线程对象
setLockHolder(current);
return true;
}
}
// reentrant (可重入的), current == getLockHolder() 表示同一个对象
else if (current == getLockHolder()) {
int nextc = c + 1;
if (nextc < 0) // overflow (状态 + 1 小于 零 为 溢出)
throw new Error("Maximum lock count exceeded");
// 设置加一后的状态值
setState(nextc);
return true;
}
return false;
}
public boolean acquire() {
// try acquire
if (tryAcquire()) {
return true;
}
// add queue and spin (添加队列和旋转)
final Thread current = Thread.currentThread();
// 如果状态不为0,线程对象不是一个,则加入队列
queue.add(current);
for (;;) {
// peek :检索但不删除此队列的头部,如果此队列为空,则返回null 。
if (current == queue.peek() && tryAcquire()) {
// TODO CAS
// 检索并删除此队列的头部,如果此队列为空,则返回null 。
queue.poll();
return true;
}
// 用于创建锁和其他同步类的基本线程阻塞原语。
LockSupport.park();
}
}
/** * 加锁 */
public void lock() {
// 比较设置状态
if (compareAndSetState(0, 1)) {
// 设置成功 , 设置 当前正在执行的线程对象的引用。
setLockHolder(Thread.currentThread());
return;
}
// 设置失败 , 尝试获取
acquire();
}
/** * 解锁 */
public void unlock() {
Thread current = Thread.currentThread();
if (current != lockHolder) {
throw new IllegalMonitorStateException("can't unlock");
}
int c = getState() - 1;
if (c == 0) {
// 状态为0 , 表示解锁, LockHolder 值为空
setLockHolder(null);
}
setState(c);
Thread waiter = queue.peek();
// 不为空,表明队列中还有线程
if (null != waiter) {
// 解除阻塞
LockSupport.unpark(waiter);
}
}
// 不安全的工具
public static Unsafe getUnsafe() {
Unsafe unsafe = null;
try {
Constructor<Unsafe> constructor = Unsafe.class.getDeclaredConstructor(new Class<?>[0]);
constructor.setAccessible(true);
unsafe = constructor.newInstance(new Object[0]);
} catch (Exception e) {
e.printStackTrace();
}
return unsafe;
}
}
编写测试类
@Slf4j
public class MyLockTest {
public static void main(String[] args) {
MyReentrantLock myReentrantLock = new MyReentrantLock();
new Thread(() -> {
log.debug("{}:开始加锁", Thread.currentThread().getName());
myReentrantLock.lock();
log.debug("{}:加锁完毕,状态为:{}",Thread.currentThread().getName(), myReentrantLock.getState());
// TimeUnit.SECONDS.sleep(2);
myReentrantLock.unlock();
log.debug("{}:解锁完毕", Thread.currentThread().getName());
log.debug("{}:解锁完毕,状态为:{}",Thread.currentThread().getName(), myReentrantLock.getState());
}, "t").start();
new Thread(() -> {
log.debug("{}:开始加锁", Thread.currentThread().getName());
myReentrantLock.lock();
log.debug("{}:加锁完毕,状态为:{}",Thread.currentThread().getName(), myReentrantLock.getState());
// TimeUnit.SECONDS.sleep(2);
myReentrantLock.unlock();
log.debug("{}:解锁完毕", Thread.currentThread().getName());
log.debug("{}:解锁完毕,状态为:{}",Thread.currentThread().getName(), myReentrantLock.getState());
}, "t1").start();
}
}
输出结果
21:43:39.108 [t1] DEBUG com.xiaozheng.cas.MyLockTest - t1:开始加锁
21:43:39.108 [t] DEBUG com.xiaozheng.cas.MyLockTest - t:开始加锁
21:44:08.973 [t1] DEBUG com.xiaozheng.cas.MyLockTest - t1:加锁完毕,状态为:1
21:44:08.973 [t1] DEBUG com.xiaozheng.cas.MyLockTest - t1:解锁完毕
21:44:08.973 [t1] DEBUG com.xiaozheng.cas.MyLockTest - t1:解锁完毕,状态为:0
21:44:09.937 [t] DEBUG com.xiaozheng.cas.MyLockTest - t:加锁完毕,状态为:1
21:44:09.937 [t] DEBUG com.xiaozheng.cas.MyLockTest - t:解锁完毕
21:44:09.937 [t] DEBUG com.xiaozheng.cas.MyLockTest - t:解锁完毕,状态为:0
自己的一点点总结
- 主要是判断状态和线程对象是否是同一个对象,来进行是否加锁
- 如果
状态不为0,线程对象不是同个,表示有线程要竞争锁,则将其线程加入队列,并暂时park该线程 - 等加锁线程执行完毕进行解锁时,会将
park的线程唤起,此时竞争该锁的线程会重新进入下轮的队列遍历,拿到当前线程进行状态设置和设置lockHolder为当前线程 - 解锁时,
状态减1,为0时,设置lockHolder为null,等待下个加锁线程赋值,队列不为空进行唤醒park
边栏推荐
- 飞腾腾锐 D2000 荣获数字中国“十大硬核科技”奖
- 【正则】判断, 手机号,身份证号
- 九方智投是正规公司吗?一起聊聊九方智投
- 768. 最多能完成排序的块 II 贪心
- 【无标题】JDBC连接数据库读超时
- Meta Quest内容生态总监谈App Lab设计初衷
- Mysql database related operations
- Connman introduction
- 04. Detailed steps for installing the simulated browser chromedriver in Google browser
- On the first day of Shenzhen furniture exhibition, the three highlights of Jin Ke'er booth were unlocked!
猜你喜欢

Network security / penetration testing tool awvs14.9 download / tutorial / installation tutorial

代码回滚,你真的理解吗?

Code review pyramid

app端接口用例设计方法和测试方法

Digital analog 1232

DTS is equipped with a new self-developed kernel, which breaks through the key technology of the three center architecture of the two places Tencent cloud database

深圳家具展首日,金可儿展位三大看点全解锁!

Interview question: the difference between three instantiated objects in string class

Process analysis of object creation

LPCI-252通用型PCI接口CAN卡的功能和应用介绍
随机推荐
The new version of Alibaba Seata finally solves the idempotence, suspension and empty rollback problems of TCC mode
Deployment of ruoyi's environment and operation of the system
flink cdc 到MySQL8没问题,到MySQL5读有问题,怎么办?
Connman introduction
GetObject call timing of factorybean
477-82(236、61、47、74、240、93)
Chapter 4 决策树和随机森林
Detailed tutorial of typera
Number of square arrays (day 81)
Double disk: the main differences between DFS and BFS, the differences in ideology, and the differences in code implementation
Source code analysis of openfeign
回归测试:意义、挑战、最佳实践和工具
Tool class of localdatetime sorted out by yourself
DTS is equipped with a new self-developed kernel, which breaks through the key technology of the three center architecture of the two places Tencent cloud database
Minimum ticket price (day 80)
Okaleido tiger is about to log in to binance NFT in the second round, which has aroused heated discussion in the community
次轮Okaleido Tiger即将登录Binance NFT,引发社区热议
C# 使用SqlSugar Updateable系统报错无效数字,如何解决?求指导!
MySQL Chinese failure
【无标题】