写锁

tryAcquire()

image.png
1. 在获取写锁时,会尝试判断当前对象是否拥有了锁(读锁与写锁),如果已经拥有且持有的线程并非当前线程,直接失败
2. 如果当前对象没有被加锁,那么写锁就会为为当前对象上锁,并且将写锁的个数加1.
3. 将当前对象的排他锁线程持有者设为自己

  1. import java.util.concurrent.TimeUnit;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantReadWriteLock;
  4. /**
  5. * 写锁的上锁流程
  6. */
  7. @Slf4j(topic = "enjoy")
  8. public class RWLock2 {
  9. //读写锁
  10. static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  11. static Lock r = rwl.readLock();
  12. static Lock w = rwl.writeLock();
  13. public static void main(String[] args) throws InterruptedException {
  14. Thread t1 = new Thread(() -> {
  15. w.lock();
  16. try {
  17. log.debug("t1 w---加锁成功");
  18. } finally {
  19. w.unlock();
  20. }
  21. }, "t1");
  22. t1.start();
  23. }
  24. }

//写锁在加锁的时候要么锁没有被人持有则会成功,要么锁是重入 否则都失败
protected final boolean tryAcquire(int acquires) {
    /*
     *1、获取当前线程
     */
    Thread current = Thread.currentThread();
    //获取锁的状态----默认是0
    int c = getState();
    //因为读写锁是同一把锁(同一个对象),所以为了表示读写锁,把锁的前16位表示读锁的状态 后16位表示写锁的状态
    //获取写锁的状态
    int w = exclusiveCount(c);
    //表示有人上了锁(maybe w or r)
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
        /*
         * 1、判断当前锁是什么锁。如果是只有读锁直接加锁失败
         * 为什么呢?因为w==0 标识这把锁从来没有上过写锁,只能是读锁
         * 而当前自己是来上写锁的所以只能是升级 故而失败
         * 2、如果需要进到第二个判断|| 标识第一个失败了也就是这把锁有可能上了写锁 也有可能上了读写锁
         * 判断是否重入 如果不是重入失败
         */
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;

        //重入 把w+1 长度有限 但是这个判断基本没用
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        //没用超出重入的最大限制 则把w+1
        setState(c + acquires);
        return true;
    }

    //writerShouldBlock 自己要不要排队
    //如果正常情况下就是当前这个例子第一次加锁
    //writerShouldBlock 判断队列当中是有有人排队 如果有人排队 如果是公平锁则自己去排队 非公平锁则不排队
    //如果是非公平则不管有没有人排队直接抢锁
    //公平 如果队列当中没人 则不需要排队则(writerShouldBlock()=false) 加锁 
    //公平 如果队列当中有人 则需要排队则(writerShouldBlock()=true) 加锁  会执行 if快当中的reture false 标识加锁失败
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires)){
         return false;
    }

    //加锁成功则把当前持有锁的线程设置自己
    setExclusiveOwnerThread(current);
    return true;
}