首页 > 编程知识 正文

java aqs,java原理面试题

时间:2023-05-03 16:00:26 阅读:129216 作者:4799

在Java中进行同步的方法包括使用同步关键字进行同步访问,以及在Java 5之后位于java.util.concurrent.locks包下的方法

实现同步访问的另一种方法是锁定。 今天,就Lock的实现类ReentrantLock在公平锁定模式下的实现方法进行说明。

java可重新锁定-重复锁定实现详细信息

ReentrantLock支持两种获取锁定的方法:公平模型和非公平模型。 在继续之前,让我们把故事元素转换成程序元素。

首先,让我们谈谈公平的摇滚模式:

初始化时,state=0表示没有人被剥夺打水权。 此时,村民A来打水(A线程要求钥匙),占打水权,state 1,如下:

线程a获得了锁定,获得了state原子性1。 此时,状态更改为1,a线程继续执行其他任务。 随后,村民b也试图打水(线程b请求锁定)。 线程b无法获取锁定,将生成节点并将其排队。 下图:

初始化时,将生成空的头节点,然后是b线程节点。 此时,如果线程a请求锁定,是否需要排队? 当然答案是否定的。 否则,就这样陷入死锁。 A再次要求钥匙,意味着在打水的过程中,同一家人来打水了。 我有特权。 此时的状态如下图所示。

到此为止,我想您已经知道了什么是锁住了。 一个线程获得锁定后,只需通过再次去获取同一锁定来累计状态值。 线程a释放一次锁定,情况就是这样。

只要减少状态值,线程a就会释放所有此锁定,并将状态值减少到0,其他线程就可以获取锁定。 当a完全解除锁定时,state将返回0,通知队列唤醒b线程节点,以便b再次冲突锁定。 当然,如果b线程后面有c线程,c线程将继续休眠并通知c线程,除非b执行完毕。 请注意,当线程节点被唤醒并锁定时,相应的节点将从队列中删除。

非公平锁定模型

如果理解前面提到的公平锁定模型,非公平锁定模型也将非常容易理解。 在线程a执行后,唤醒线程b需要时间,并且线程b唤醒后再次竞争锁定,因此如果线程c在切换过程中到来,则线程c可能获得锁定,而如果c获得锁定,则b乖乖地继续休眠这里不要画画了。

可重入锁

如果锁有重新输入的可能性,则称为可重新输入锁。 这是一种可重读的锁,如同步和延迟锁定,可重读性实际上表明了锁的分配机制。 不是基于方法调用的分配,而是基于线程的分配。 举个简单的例子,如果一个线程运行到某个synchronized方法(例如method1),并且在method1中调用另一个synchronized方法method2,则线程不会重新申请锁定,而是

看看下面的代码就知道了。

class MyClass {

公共同步语音方法1 (

method2(;

}

公共同步语音方法2 (

}

}

上述两个方法method1和method2都是同步限定的,但是如果线程a在某个时间点运行到method1,则线程a获得了该对象的锁定,而method2也是同步的如果同步不可重新输入,则线程a会继续等待永远无法获取的锁定,因为线程a已经具有该对象的锁定,并且正在申请获取该对象的锁定

另一方面,由于同步和锁定都具备重新输入的可能性,因此不会发生上述现象。

接下来,开始真正的源代码分析。

公共语言(布尔故障) {

sync=fair? newfairsync (: newnonfairsync );

}

ReentrantLock的构造方法现在只看公平锁。 实现FairSync

staticfinalclassfairsyncextendssync {

privatestaticfinallongserialversionuid=-3000897897090466540 l;

final void锁定

acquire(1;

}

//*

* fairversionoftryacquire.don ' tgrantaccessunless

* recursivecallornowaitersorisfirst。

*/

保护性金融

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;

}

}

当调用lock方法时,会调用acquire(1)方法,获取state,state等于0表示没有线程获取到锁,接下来会判断是否有等待的线程,如果没有等待线程和进行cas操作state成功,则设置当前独占线程为当前线程,返回true,获取锁成功。后面有个else条件就是可重入锁的实现,如果获取锁失败,则判断当前独占锁线程是否为当前线程

,如果是当前线程,则将state进行加一操作,并返回true,获取锁成功。否则获取锁失败。

注意事项:state 使用了volatile关键字,使state被线程修改时,及时的被其他线程读取到最新的值。

AbstractQueuedSynchronizer

public final void acquire(int arg) {

if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

尝试获取锁,当获取锁失败后,将当前线程放入等待队列中,然后开始循环去获取锁操作。

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;

try {

boolean interrupted = false;

for (;;) {

final Node p = node.predecessor();

if (p == head && tryAcquire(arg)) {

setHead(node);

p.next = null; // help GC

failed = false;

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

如果已经没有线程获取锁的时候,则返回true,当前锁线程进行interrupt操作,

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。