hello~各位读者好,我是鸭血粉丝(你们能够称呼我为「阿粉」)。今天,阿粉带着你们来了解一下
ReentrantLock
锁的非公平锁的实现原理java
1.锁
java中,加锁的方式web
1. synchronized,这个是 java 底层实现的,也就是 C 语言实现的。
2. lock,这个是 java.util.concurrent 包下面的,是 java语言实现的。
2.ReentrantLock
ReentrantLock 是 Lock 的一种实现,是一种可重入的公平或非公平锁。默认是非公平锁。微信
2.1 Lock的建立
首先看下锁的建立和使用代码:app
//建立锁Lock lock = new ReentrantLock();//加锁lock.lock();//释放锁lock.unlock();
而后看下建立的是 ReentrantLock 的构造函数:less
public ReentrantLock() { sync = new NonfairSync();}
NonfairSync 就是非公平锁。因此 ReentrantLock 默认是非公平锁的实现编辑器
2.2 lock()
加锁的逻辑就比较复杂了,由于存在线程竞争。因此有两种状况,一种是竞争到锁的处理,一种是没有竞争到锁的处理。函数
首先咱们仍是来看下 lock() 方法,由于最终是非公平的实现,因此直接看 NonfairSync 里面的 lock 方法。oop
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1);}
2.3 没有获取到锁的逻辑 acquire()
直接上代码:学习
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();}
仍是3个方法,阿粉一个一个的说。flex
-
tryAcquire(arg) ,仍是先看代码在分析。
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { 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;}
a. 获取 state ,若是等于0,说明以前得到锁的线程已经释放了,那么这个线程就会再次去竞争锁,这就是非公平锁的体现,若是是公平锁,是没有这个判断的。
b. 若是前一个得到锁的线程没有释放锁,那么就判断是不是同一个线程,是的话就会将 state 加 1。这个就是重入锁的体现。
c. 若是都不知足,那么返回 false。
-
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) ,再次获取锁没有成功,而且又不是可重入锁,那么就存入一个阻塞队列里面。里面还有一点逻辑,就不展开了,有兴趣能够本身看下。
-
selfInterrupt(); 这个是当前线程的中断标志,做用就是在线程在阻塞的是否,客户端经过调用了中断线程的方法 interrupt(),那么该线程被唤醒的时候,就会有响应的处理。具体要看这个线程 run 方法里面的代码逻辑。
2.4 unlock()
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;}
释放锁的步骤
-
state - 1,若是大于0,说明释放的是重入锁,只须要修改 state 就好了 -
若是等于0,说明要释放锁,释放锁首先须要把独占线程设置为null,再把state设置为0。
3 总结
Lock 锁的实现:
-
互斥性:须要一个状态来判断是否竞争到锁:state 而且须要用 volatile修饰,保证线程之间的可见性。
-
可重入性:Thread exclusiveOwnerThread 这个成员变量来记录当前得到锁的线程。
-
公平或非公平:默认非公平,NonfairSync。
-
没有竞争到锁的线程怎么办?放到队列中。
-
没有竞争到锁的线程怎么释放CPU?park:阻塞线程释放CPU资源,这个操做在 acquireQueued(),阿粉没没有讲这个。
-
最后来张流程图:
< END >
若是你们喜欢咱们的文章,欢迎你们转发,点击在看让更多的人看到。也欢迎你们热爱技术和学习的朋友加入的咱们的知识星球当中,咱们共同成长,进步。
本文分享自微信公众号 - Java极客技术(Javageektech)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。