您的位置:首页 > 其它

高并发学习笔记(六)

2019-03-26 11:21 141 查看

二、同步器的实现(二)

3.ReentrantLock

    ReentrantLock是个可重入的互斥锁,具有与使用synchronized同步代码访问monitor对象相同的一些基本行为和语义,但是ReentrantLock更加强大并且效率要高一些。下面看个示例:

/**
* ReentrantLock示例
* Created by bzhang on 2019/3/17.
*/
public class TestReentrantLock {
private ReentrantLock lock = new ReentrantLock();

public void m1(){
lock.lock();      //获取锁,若锁被别的线程占用则阻塞等待获取锁
try {
System.out.println(Thread.currentThread().getName()+"开始占着茅坑了");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"占了3小时的茅坑");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//lock.unlock();    //解锁,锁用完后一定要解锁,不然其他线程无法获取到锁,会一直阻塞
}
}

public void m2(){
System.out.println(Thread.currentThread().getName()+"也想用茅坑,但被占着了");
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"终于等到了");
}finally {
lock.unlock();
}
}

public static void main(String[] args) {
TestReentrantLock test = new TestReentrantLock();
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new Runnable() {
@Override
public void run() {
test.m1();
}
});
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.submit(new Runnable() {
@Override
public void run() {
test.m2();
}
});
pool.shutdown();
}
}

    知道了简单的用法,我们来看看ReentrantLock,其继承关系如下图,实现了Lock接口。

    Lock接口中有如下待实现方法:

public interface Lock {

//获取锁,若锁不可用(拿不到锁),就让当前线程休眠
void lock();

//获取锁,但是在等待获取时可被中断
void lockInterruptibly() throws InterruptedException;

//尝试获取锁,即锁当前未被其它线程占用,则获取锁返回true,若锁被占用,不等待直接返回false
boolean tryLock();

//在一定时间内尝试获取锁,若在规定时间内成功获取就返回true,否则就返回false。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

//解锁/释放锁,持有锁的线程才能释放锁,因此使用完锁一定要释放,不然会造成死锁。
void unlock();

//返回绑定到此锁的condition实例
Condition newCondition();
}

    接口看完,来看看ReentrantLock是如何实现的,先看看构造方法:

private final Sync sync;    //同步队列

//空构造
public ReentrantLock() {
sync = new NonfairSync();    //创建一个非公平的同步队列,是AQS的子类实现
}

//根据fair构造
public ReentrantLock(boolean fair) {
//根据fair创建一个公平或非公平同步队列
sync = fair ? new FairSync() : new NonfairSync();
}

    由构造方法可知,ReentrantLock实际是创建了一个同步队列,NonfairSync或者FairSync。他们都是AQS的实现类,实现了AQS的独占模式,其中NonfairSync是非公平模式下竞争锁资源,即线程竞争锁资源时不以等待时间长短来决定。而FairSync则是公平模式下获取锁资源,即按照线程等待时间的长短来决定洗个获取锁资源的是谁,其继承关系如下图:

    下面先看看公平同步队列及非公平同步队列的实现源码:

//ReentrantLock中FairSync的实现

//公平同步队列实现类
static final class FairSync extends Sync {
//尝试获取锁资源,若未获取成功则进入同步队列中等待
final void lock() {
//不可被中断的尝试获取锁方法
//前面分析AQS时已经分析过了,此处只要知道在进入等待队列之前acquire方法会调用
//tryAcquire方法先尝试获取锁即可,若获取锁失败则会加入同步队列中等待(因为acquire中调用了acquireQueued方法)
acquire(1);
}

//尝试获取锁,AQS实现类必须重写的方法。
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
int c = getState();    //获取AQS同步队列状态值
//判断同步状态值是否为0,为0即锁资源当前处于释放状态,竞争锁
//不为0表示已经有线程获取到锁,直接去判断当前线程是否是拥有锁的线程
if (c == 0) {
//hasQueuedPredecessors是AQS中的方法,查询是否存在比当前线程等待时间更久的线程
//若不存在,表示当前线程的等待时间就是最长的,那么就尝试更新同步队列的状态值为acquires
//若当前线程是等待最久且同步队列状态值成功更新为acquires,那么就将当前线程设置为拥有独占访问的线程(即获取到锁资源)
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;
}
}

//非公平同步队列的实现类
static final class NonfairSync extends Sync {
//尝试获取锁资源,若未获取成功则进入同步队列中等待
final void lock() {
//直接尝试设置同步状态值,若成功表示获取到锁资源,直接将当前线程设为拥有锁资源的线程
//设置不成功在去尝试获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

//尝试获取锁操作,调用父类的nonfairTryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

//NonfairSync及FairSync的公共父类
abstract static class Sync extends AbstractQueuedSynchronizer {

abstract void lock();    //抽象获取锁方法,子类实现,若为获取到锁,则进入同步队列等待

//非公平的尝试获取锁对象
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();    //当前线程
int c = getState();    //获取同步队列的状态值
//判断状态值是否为0,即锁是否未被其他线程获取
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;
}

//尝试释放锁资源
protected final boolean tryRelease(int releases) {
int c = getState() - releases;    //获取当前队列的状态值,并得到想要更新的状态值
//判断当前线程是否是拥有锁资源的线程,不是抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;    //释放锁是否成功的标识
//若更新的状态值为0,表示线程将释放锁
//不为0,表示是重入锁,尚未到达释放状态
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);    //更新状态
return free;
}

//判断当前线程是否是拥有锁资源的额线程
protected final boolean isHeldExclusively() {

return getExclusiveOwnerThread() == Thread.currentThread();
}

//新建条件队列
final ConditionObject newCondition() {
return new ConditionObject();
}

//返回当前独占锁资源的线程,若锁已被释放则返回null
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}

//返回同步状态值,若大于0锁资源处于独占状态,且可表示重入的次数。
//返回为0表示处于释放状态
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}

//判断锁资源是否处于占用状态
final boolean isLocked() {
return getState() != 0;
}

private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}

    以上就是ReentrantLock中公平锁及非公平锁底层的同步队列的实现,下面看看ReentrantLock的源码:

public class ReentrantLock implements Lock, java.io.Serializable {
//尝试获取锁方法,锁锁资源已被其他线程占用,则阻塞当前线程以等待获取锁
//实际是调用底层同步队列的lock方法
public void lock() {
sync.lock();    //实际调用的获取锁方法
}

//可被中断的尝试获取锁的方法
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);    //调用AQS中的方法实现
}

//尝试获取锁,以非公平方式尝试获取锁,只尝试一次,获取不到不会等待直接返回
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}

//在一定时间内尝试获取锁,若在timeout时间内成功获取,返回true,超时则返回false
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

//释放锁,必须要拥有锁才能释放,不然抛异常
public void unlock() {
sync.release(1);
}

//返回与当前锁资源相关的条件队列
public Condition newCondition() {
return sync.newCondition();    //实际是新建一个条件等待队列
}

//查看拥有锁的线程的重入次数
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;
}

//获取当前拥有锁的线程,若锁资源处于释放状态,则返回null
protected Thread getOwner() {
return sync.getOwner();
}

//查看是否有线程等待获取锁,即同步队列是否为空
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}

//查看thread线程是否是等待获取锁的一员
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}

//查看等待获取锁的线程数的估计值
public final int getQueueLength() {
return sync.getQueueLength();
}

//获取同步队列中等待获取锁的线程列表
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}

//condition等待队列中是否有等待条件的结点
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);
}

//获取给定的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);
}

//获取给定condition条件队列中等待线程的线程列表
protected Collection<Thread> 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);
}
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: