要讲ReentrantLock,首先离不开Lock,因为它实现了Lock接口,先讲下Lock接口
Lock是Java的一个锁策略,相对于synchronized:
1.Lock更加灵活,随着线程数量的增加,效率不会降低,反之synchronized关键字则会效率成反比下降;
2.Lock提供多种加锁方案,这里从源码可以看出来,下面会讲到
3.对于单线程来说,synchronized关键字效率高于Lock,可以根据场景自己选择需要哪种策略
接下来讲下Lock的源码:
———lock.lock()
获取锁
———lock.lockInterruptibly()
获取锁,除非当前线程被中断
———lock.tryLock()
获取锁,但有一个条件就是锁这个时候处于空闲状态
———lock.tryLock(long time ,time unit)
获取锁,但有一个条件就是锁这个时候处于空闲状态,在这个基础上加上一个等待时间
———lock.unLock()
释放锁
———lock.newCondition()
获取一个Condition实例,这个实例可以跟Lock实例绑定使用;而Condition的作用,就是与Lock对象结合使用,替代对象监视器
接下来讲下ReentrantLock类的源码:
首先来看下构造方法
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
在默认不传参数的时候,得到的是非公平锁,为什么会这样写呢,我认为是非公平锁相对于公平锁来说,效率更高;
继续往下面看,有个sync类,
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer
根据解释,这个类为同步控制基础类;我们可以从接下来的公平锁和非公平锁可以看出来,这个类的作用
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* 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);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
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) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
相信大家看到这里,已经看到了公平锁和非公平锁,有两个地方不一样,我先贴下
nonfairTryAcquire(acquires)这个方法的代码
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;
}
这里可以跟FairSync中的
tryAcquire(int acquires)方法比较一下
发现只有这里的不同
即hasQueuedPredecessors(),一个判断了这个状态,另一个没有
贴下这个方法的代码
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
这个方法的意思就是说,线程等待的时间不比当前线程的时间更长
如果返回false,即等待的时间比当前线程等待的时间更长,即为公平锁中获取锁的判断条件,否则为非公平锁。
其次还有一个地方,就是锁的lock方法;
//非公平锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
//公平锁
final void lock() {
acquire(1);
}
这里我再贴下非公平锁中,if判断里面的方法
/**
* Atomically sets synchronization state to the given updated
* value if the current state value equals the expected value.
* This operation has memory semantics of a {@code volatile} read
* and write.
* 如果当前状态值等于预期值,自动将同步状态设置为给定的更新状态值
此操作的内存语义为volatile读写。
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
return U.compareAndSwapInt(this, STATE, expect, update);
}
/**
* Sets the thread that currently owns exclusive access.
* 设置当前拥有独占访问权的线程。
* A {@code null} argument indicates that no thread owns access.
* This method does not otherwise impose any synchronization or
* {@code volatile} field accesses.
* @param thread the owner thread
*/
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
这里的意思也就是说,在非公平锁中,调用lock方法时,多加了一个状态值判断,根据这个判断,来设置下一个有锁的访问权的线程。这里我可能还没有讲明白,大家可以查看下
sun.misc.Unsafe U= sun.misc.Unsafe.getUnsafe();
U.compareAndSwapInt(this, STATE, expect, update);
这个方法的具体实现,相信会有一个理解。
到这里,对公平锁和非公平锁的定义和条件就讲解完毕了。
接下来看看ReentrantLock的其他方法,我这里只讲ReentrantLock独有的方法,由Lock实现来的方法不做讲解,用法和解释一样:
//查询当前线程持有多少个锁
public int getHoldCount() {
return sync.getHoldCount();
}
//查询当前线程是否持有这个锁
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
//查询锁是否被某一个线程所持有
public boolean isLocked() {
return sync.isLocked();
}
//判断是否为公平锁
public final boolean isFair() {
return sync instanceof FairSync;
}
//返回当前拥有锁的线程,或者为空
protected Thread getOwner() {
return sync.getOwner();
}
//查询是否有线程在等待获取这个锁
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
//查询某个线程是否在等待获取这个锁
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
//返回等待此锁的线程总数
public final int getQueueLength() {
return sync.getQueueLength();
}
//返回可能等待获取此锁的集合
protected Collection getQueuedThreads() {
return sync.getQueuedThreads();
}
//查询是否有线程在等待某个指定条件下关联的锁
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回在等待某个指定条件下关联的锁的线程总数
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回可能在等待某个指定条件下关联的锁的线程的集合
protected Collection getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回锁的描述以及状态
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
源码看到这里,基本就讲解完毕了,可能大家的疑问点,还是在公平锁和非公平锁,具体是如何实现的,这个就得往下面继续深究了。我会继续研究,后续再出一篇关于这两个实现的文章,目前我还没有完全理解源码。
最后,给大家提供一个公平锁和非公平锁的简单用法例子:
package com.dhc.jstestdemo.lock;
import android.util.Log;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 大漠dreamer on 2019/3/20.
*/
public class LockTest {
public static final String TAG = LockTest.class.getSimpleName();
//创建锁
private ReentrantLock mLock;
public LockTest() {
}
private LockTest(ReentrantLock mLock) {
this.mLock = mLock;
}
/**
* 设置锁
*/
private void setLock(ReentrantLock lock) {
try {
lock.lock();
if (lock.isFair()) {
Log.d(TAG, "setFairLock: " + Thread.currentThread().getName() + "get Fair Lock");
} else {
Log.d(TAG, "setFairLock:" + Thread.currentThread().getName() + " get Unfair Lock");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 测试锁
*
* @param lock
*/
private void testLock(final ReentrantLock lock) {
final LockTest fairLock = new LockTest(lock);
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: " + Thread.currentThread().getName() + "running");
fairLock.setLock(lock);
}
};
Thread[] threads = new Thread[5];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(runnable);
threads[i].start();
}
}
public void test() {
testLock(new ReentrantLock(true));
testLock(new ReentrantLock(false));
}
}
给出最终执行的结果:
文章到这就结束了,谢谢阅读,有什么问题还请大家指出来,共同进步~