代码来源: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