赞
踩
ReentantLock的特点如下:
事实上,上面的很多东西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,票卖完了我没抢到 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。