分析
ReentantLock的特点如下:
- 首先是继承自AQS的
- 可中断
- 可以设置超时时间
- 可以切换公平锁/非公平锁
- 支持多个条件变量
- 支持可重入
事实上,上面的很多东西AQS已经帮忙实现了,所以想要复刻一个不是很难。仔细观察一下源码,我们需要重写的接口只有以下几个:
- 新建一个自己的
MyReentrantLock
类,实现了Lock
接口 - 在
MyReentrantLock
里面,新建一个NonfairSync
类,继承自AbstractQueuedSynchronizer
- 在
NonfairSync
里面需要实现如下接口:
void lock();
boolean tryAcquire();
boolean tryRelease();
至于为什么需要实现这三个接口,看如下注释:
总的来说:实现lock()
是因为我们要实现可重入的话,需要自己写逻辑补充;
实现tryAcquire()
,则是因为提供一种机制,让任务尽量可能在进入阻塞队列之前,能获取到锁。因为,进了阻塞队列之后可能会反复阻塞和解除阻塞(经历上下文切换),这个代价是昂贵的;
实现tryRelease()
,则是因为这个方法是【释放锁】的核心方法。想要实现可重入的逻辑就得维护这个方法。
源码
为了方便,这里只是简单实现了一个非公平锁的代码。
public class MyReentrantLock implements Lock {
/**
* 锁实例
*/
private NonfairSync sync;
/**
* 构造放啊
*/
public MyReentrantLock() {
sync = new NonfairSync();
}
@Override
public void lock() {
sync.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
/**
* 非公平锁的实现方式
*/
public static final class NonfairSync extends AbstractQueuedSynchronizer {
/**
* 非公平锁,上锁方法
*/
public void lock() {
// CAS操作锁
boolean result = compareAndSetState(0, 1);
if (result) {
// 设置成功,则修改独占状态
setExclusiveOwnerThread(Thread.currentThread());
} else {
// 设置不成功,则准备入等待队列
acquire(1);
}
}
/**
* 实现AQS对tryAcquire的方法
*
* <p>
* 以下是AQS的解释:
* 以独占模式获取,忽略中断。通过调用至少一次tryAcquire实现,成功时返回。
* 否则,线程将被排队,可能会反复阻塞和解除阻塞,调用tryAcquire直到成功。
* 这个方法可以用来实现方法Lock.lock。
* </p>
*/
@Override
protected boolean tryAcquire(int acquires) {
return doTryAcquire(acquires);
}
/**
* 实现AQS的tryRelease方法
*
* <p>
* 通用场景
* 术语库
* 尝试将状态设置为在独占模式下反映释放。
* 此方法总是由执行释放的线程调用。
* 默认实现抛出UnsupportedOperationException。
* 参数:
* Arg -释放参数。该值始终是传递给释放方法的值,或者是进入条件等待时的当前状态值。否则该值是不解释的,可以表示您喜欢的任何内容。
* 返回:
* 如果该对象现在处于完全释放状态,则为True,以便任何等待的线程都可以尝试获取;否则为假。
* 抛出:
* IllegalMonitorStateException -如果释放会使同步器处于非法状态。此异常必须以一致的方式抛出,才能使同步正常工作。
* UnsupportedOperationException -如果不支持独占模式
* </p>
*/
@Override
protected boolean tryRelease(int releases) {
final Thread thread = Thread.currentThread();
if (thread != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
int state = getState();
int newState = state - releases;
// 接口要求,完全释放则true,反之false
boolean fullyRelease = false;
if (newState == 0) {
fullyRelease = true;
setExclusiveOwnerThread(null);
}
setState(newState);
return fullyRelease;
}
private ConditionObject newCondition() {
return new ConditionObject();
}
/**
* 实现非公平模式下的tryAcquire
*/
private boolean doTryAcquire(int acquires) {
final Thread currentThread = Thread.currentThread();
int state = getState();
if (state == 0) {
// 再次竞争一下
boolean result = compareAndSetState(0, acquires);
if (result) {
setExclusiveOwnerThread(currentThread);
return true;
}
} else {
// 判断是否为可重入
Thread exclusiveOwnerThread = getExclusiveOwnerThread();
if (exclusiveOwnerThread == currentThread) {
// 做可重入的逻辑
return doReentrantLock(state + acquires);
}
}
return false;
}
private boolean doReentrantLock(int newState) {
if (newState < 0) {
throw new Error("可重入次数已达上限");
}
setState(newState);
return true;
}
}
}
使用示例
public class MyReentrantLockTest {
// 票数
public static int tickets = 8;
// 总人数
public static final int PERSONS = 10;
public static final Lock LOCK = new MyReentrantLock();
public static void main(String[] args) {
for (int i = 0; i < PERSONS; i++) {
new Thread(() -> {
buyTicket();
}).start();
}
}
public static void main1(String[] args) {
MyReentrantLock lock = new MyReentrantLock();
lock.lock();
try {
System.out.println("试试看");
lock.lock();
try {
System.out.println("可重入了");
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
}
public static void buyTicket() {
// 获取锁
LOCK.lock();
try {
Thread.sleep(1000);
if(tickets > 0) {
System.out.println("我是" + Thread.currentThread().getName() + ",我来抢第【" + tickets-- + "】张票");
} else {
System.out.println("我是" + Thread.currentThread().getName() + ",票卖完了我没抢到");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放说
LOCK.unlock();
}
}
// 系统输出如下:
// 我是Thread-0,我来抢第【8】张票
// 我是Thread-1,我来抢第【7】张票
// 我是Thread-2,我来抢第【6】张票
// 我是Thread-3,我来抢第【5】张票
// 我是Thread-4,我来抢第【4】张票
// 我是Thread-5,我来抢第【3】张票
// 我是Thread-9,我来抢第【2】张票
// 我是Thread-7,我来抢第【1】张票
// 我是Thread-8,票卖完了我没抢到
// 我是Thread-6,票卖完了我没抢到
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/180525.html