Analyze the CAS, reentrant lock, and unfair lock written by the CSDN boss

Code source: https://blog.csdn.net/kkgbn/article/details/100136988

Add comments that you understand to its code

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;
	}
}

write test class

@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();
    }
}

output result

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

my little summary

  • It is mainly to judge whether the state and the thread object are the same object, so as to whether to lock
  • If 状态不为0, 线程对象不是同个, indicates 有线程要竞争锁, it will 线程加入队列, and temporarily parkthe thread
  • When the lock thread finishes executing and unlocks, parkthe thread will be awakened. At this time, the thread competing for the lock will re-enter the next round of queue traversal, get the current thread to set the state and set it lockHolderas the current thread
  • When unlocking, 状态减1, when it is 0, set it lockHolderto nullwait for the next lock thread assignment, and wake up if the queue is not emptypark

Guess you like

Origin blog.csdn.net/u013494827/article/details/126004254