美文网首页
可重入锁ReentrantLock-java并发编程(二)

可重入锁ReentrantLock-java并发编程(二)

作者: 卫渐行 | 来源:发表于2018-09-26 13:31 被阅读24次

通过介绍ReentrantLock中的3个内部类,分别是Sync、FairSync和NonfairSync;其中后面的两者继承前面的Sync,同时Sync是一个独占锁(exclusive)下;我们通过分析tryAcquire,tryRelease的源码来分析ReentrantLock的实现

FairSync和NonfairSync的独占功能实现

  • 公平锁(FairSync):每个线程抢占锁的顺序为先后调用lock方法的顺序依次获取锁;tryAcquire的具体实现如下:
 final void lock() {
            acquire(1);
        }
 /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
//  /如果队列中没有其他线程  说明没有线程正在占有锁!且当前的state为o;这个是和nonfairsync的区别
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
//如果不为0 意味着,锁已经被拿走了,但是,因为ReentrantLock是可重入锁,
//是可以重复lock,unlock的,只要成对出现行。一次。这里还要再判断一次 获取锁的线程是不是当前请求锁的线程。
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
  • 非公平锁(NonfairSync):每个线程抢占锁的顺序不定,谁运气好,谁就获取到锁,和调用lock方法的先后顺序无关,类似于堵车时,加塞的那些XXXX。具体源码实现如下
        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {

            if (compareAndSetState(0, 1))
      //如果当前线程不是用独占的方式占有;则将当前线程设为独占方式。即立即抢夺资源执行;
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
/**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
//注意下:不断地尝试修改state状态,
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

公平锁和非公平锁获取锁的区别

  • 公平锁: 首先先读取状态位state,然后再做判断,之后使用cas设置状态位。能获取锁的线程就获取锁,不能获取锁的线程被挂起进入队列。之后再来的线程的等待时间没有已经在队列里的线程等待时间长,所以会一直进入等待队列。 公平锁类似于排队买火车票一样,后面来的人没有前面来的人等待时间长,会一直在队尾被加入到队列里。需要判断队列中有没有被其他线程占有~~
  • 非公平锁:尝试通过使用CAS判断设置状态位,是一种抢占式的方式。同时非公平锁也没有等待时间长的线程会优先获取锁这个概念。非公平锁类似吃饭排队,但是总会有那么几个人试图插队。

锁的释放

  • 两种锁都继承父类的Sync的tryRelease方法;
 protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

参考地址:
JDK1.8 AbstractQueuedSynchronizer的实现分析(上)http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer
Java可重入锁ReentrantLock分析 https://fangjian0423.github.io/2016/03/19/java-ReentrantLock-analysis/

相关文章

网友评论

      本文标题:可重入锁ReentrantLock-java并发编程(二)

      本文链接:https://www.haomeiwen.com/subject/nuswnftx.html