4. Get unsafe
import sun.misc.Unsafe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author sz
* @DATE 2022/3/16 20:30
*/
public class MyReentrantLock implements Lock {
//记录锁状态 0 -> 锁可用 1-> 锁被占 >1 -> 锁重入
private int status = 0;
private long offset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("status"));
private static Unsafe unsafe;
static {
try {
unsafe = getUnsafe();
} catch (Exception e) {
e.printStackTrace();
}
}
public MyReentrantLock() throws NoSuchFieldException {
}
public static Unsafe getUnsafe() throws Exception {
//利用反射
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true); // 设置为可见
Unsafe unsafe = (Unsafe) theUnsafe.get(null); // 获取Unsafe对象
return unsafe;
}
@Override
public void lock() {
new ReentrantLock().lock();
}
@Override
public void unlock() {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public Condition newCondition() {
return null;
}
}
Then you can do whatever you want haha
5. Get the trylock method
How to write the whole process as above code?
First, if judgment tries to modify the value of status
if (unsafe.compareAndSwapInt(this,offset,0,1))
offset ==> status offset in memory
If the value of status is 0, change it to 1 and return true, otherwise return false
Return true to record the current lock is held by which thread and who will use the lock to unlock it later
//将当前锁的主人设置为当前线程
master_thred = Thread.currentThread();
return true;
If the attempt to modify the value of status fails to determine whether the lock is reentrant, if it is the lock reentrancy, the value of status will be +1 and return true
//判断是否锁重入
if (Thread.currentThread()==master_thred){
//如果是锁重入 状态值 +1
unsafe.getAndAddInt(this,offset,1);
//锁重入成功
return true;
If none of the above conditions are met, return false directly
So the tryLock method is rewritten like this
@Override
public boolean tryLock() {
//如果 status的值是 0 没有人用锁 改成1
if (unsafe.compareAndSwapInt(this,offset,0,1)){
//将当前锁的主人设置为当前线程
master_thred = Thread.currentThread();
return true;
}else {
//判断是否锁重入
if (Thread.currentThread()==master_thred){
//如果是锁重入 状态值 +1
unsafe.getAndAddInt(this,offset,1);
//锁重入成功
return true;
}
}
return false;
}
Let's test a thread trying to lock three times and try lock reentrancy
The first time the trylock method is called, the value of status is exactly 0, the modification is successful and the current thread is recorded as the holder of the lock. The second loop attempts to modify the value and fails to enter the judgment statement
The current thread happens to be the holder of the lock, so the value of status is +1 for the third cycle and the same is true
So far trylock method is done
6. Get the lock method
The difference between the lock method and the trylock method is that the trylock method is to try to acquire the lock and return true, if not, it will return false, and it will not block here.
And the lock method returns immediately after acquiring the lock, and waits until the lock is not acquired, and continues to wait until it wakes up and continues to grab the lock.
First create a waiting queue for a thread that does not grab the lock and enter the waiting queue to wait
//获取锁失败的线程的等待队列
LinkedBlockingQueue<Thread> waitQueue = new LinkedBlockingQueue<>();
@Override
public void lock() {
//如果没有获取到锁
if (!tryLock()){
//将当前线程加入等待队列
waitQueue.add(Thread.currentThread());
//循环不停抢锁
while (true){
//不停尝试抢锁
if (tryLock()){
//抢到了 从队列中剔除
//poll() 检索并删除此队列的头部,如果此队列为空,则返回 null 。
waitQueue.poll();
//跳出循环
break;
}else {
//没有抢到 阻塞等待 等待被唤醒
unsafe.park(false,0);
}
}
}
}
7. Get the unlock method
First, we need to clarify these two issues
- Who will unlock it?
- How will unlocking change?
Whoever unlocks is, of course, the owner of the lock, which is the thread recorded by master_thred
What changes will unlocking locks? In the end, it is to judge a flag bit and its different states represent different states of the lock, that is, to change the value of status and then see if there are other waiting threads in the waiting queue to wake them up
After figuring out these two points, start writing code
@Override
public void unlock() {
//首先判断锁的持有者是不是当前线程
if (Thread.currentThread() != master_thred) {
//前朝的剑怎么斩本朝的官
throw new RuntimeException("释放锁失败,当前线程:" + Thread.currentThread() + "未持有锁");
}
//能过前面的if判断 说明当前锁是被人占用的 且是当前线程占有的
//修改status的值
if (unsafe.getAndAddInt(this, offset, -1) > 0) {
if (unsafe.getInt(this, offset) == 0) {
//如果当前status==0也就是没有线程持有锁了
master_thred = null;
//再从等待队列中拿出等待线程
if (waitQueue.size()!=0) {
//注意这个 peek 方法 不会把线程从队列中删除 因为即时唤醒也有可能拿不到锁
//真正从队列中删除要等到 抢到锁了 调用 poll 方法
Thread peek = waitQueue.peek();
//唤醒线程
if (peek != null) {
unsafe.unpark(peek);
}
}
}
} else {
//重置锁
unsafe.putInt(this, offset, 0);
//锁已经被释放了 抛出异常
throw new RuntimeException("释放锁失败,锁已经被释放");
}
}
At this point, is it okay to rewrite the trylock method of the lock interface, the lock method and the unlock method?
Leave it for everyone to test and welcome to leave a message in the comment area