写到崩溃!!!我的泪水黄河都装不下了!!!!!!
T__T 不能口吐芬芳
csdn说脏字 审核都不通过 气死我了
文章目录
ReentrantLock存在的意义ReentrantLock与Synchronized的区别底层实现是否可手动释放锁是否可中断等待锁的线程,否则请求锁失败必须无限等待synchronized等待锁时不响应中断,只改标识位lockInterruptibly 等待锁时响应中断,抛出异常->lockInterruptibly()函数抛出异常->上锁失败or不排队
锁是否可以绑定条件(挖坑 Condition还没看,也没用过)tryLock(notfairSync的nonfairTryAcquire方法)可以解决一些用synchronized解决很繁琐的死锁问题非块结构的锁(粒度更细) (挖坑!!!啊啊啊啊啊啊让我死了算了)
公平锁的上锁acquire(int arg) 【加锁】tryAcquire(int acquires) 【尝试加锁】hasQueuedPredecessors() 【队是否为空or是否重入】acquireQueued(final Node node,int arg) 【排队(tryAcquire()/prak)】shouldParkAfterFailedAcquire(Node pred,Node node)/parkAndCheckInterrupt() 【是否应该自旋】addWaiter(Node mode)/enq(final Node node) 【添加节点到队列中】总结上锁过程(挖坑 一总结就头疼)
公平锁的解锁release(int arg) 【解锁】trylease(int releases) 【尝试解锁,解到0就算成功】unparkSuccessor(Node node) 【将node下一节点线程唤醒】总结解锁过程(挖坑)
非公平锁源码与公平锁性能对比
应用场景(烦死了!不想写!这玩意儿咋这么多 好累挖坑)🔗
ReentrantLock存在的意义
ReentrantLock与Synchronized的区别
底层实现
synchronized 是JVM层面的锁,是Java关键字,重量级锁通过monitor对象来完成(monitorenter与monitorexit),对象只有在同步块或同步方法中才能调用wait/notify方法。synchronized 的实现涉及到锁的升级,具体为无锁、偏向锁、自旋锁、向OS申请重量级锁。 sychronized:访问锁时分别是去CAS对象头的线程ID,对象头指向锁记录的指针,以及Monitor里面的owner等(对于重量锁涉及到哪些os的,我真不知道!!啊啊啊,毕竟看不太懂源码,也不想看)。ReentrantLock实现则是代码层面保证线程操作的原子性和volatile保证数据可见性。(比如AQS的state用volatile修饰)。 ReentrantLock:访问锁时通过访问链表第一个节点的线程判断是否重入以及去CAS AQS的state来tryAccquire.
是否可手动释放锁
synchronized 不需要用户去手动释放锁,synchronized 代码执行完后系统会自动让线程释放对锁的占用;ReentrantLock则需要用户去手动释放锁,如果没有手动释放锁,就可能导致死锁现象。一般通过lock()和unlock()方法配合try/finally语句块来完成,使用释放更加灵活,一个灵活的加锁机制提供了更好的活跃度和性能,也带了了危险。
是否可中断等待锁的线程,否则请求锁失败必须无限等待
Synchronized对于中断的处理。
synchronized关键字:线程在等待锁的时候被中断的话不会去处理它
isInterrupted=true,假如进入同步块里面,有sleep()的话会抛出睡眠时被中断异常。
假如不存在可以抛出InterruptedException异常的情况,可能就不会被发现。
与ReentrantLock的.lock()方法处理中断机制一样
ReentrantLock的.lockInterruptibly()对于中断的处理。
lockInterruptibly 等待锁时响应中断,抛出异常->lockInterruptibly()函数抛出异常,则不排队了或者上锁失败了。
synchronized等待锁时不响应中断,只改标识位
package demo
.test
;
import static java
.lang
.Thread
.sleep
;
public class Test {
public synchronized void cal() throws InterruptedException
{
System
.out
.println(Thread
.currentThread().getName()+"进来了");
System
.out
.println(Thread
.currentThread().isInterrupted());
try{
sleep(5000);
}catch (Exception e
){
System
.out
.println("啊这");
}
System
.out
.println(Thread
.currentThread().getName()+"马上要退出了");
}
public static void main(String
[] args
) throws InterruptedException
{
Test test
=new Test();
Thread t1
=new Thread(new Runnable() {
@Override
public void run() {
try {
test
.cal();
} catch (InterruptedException e
) {
}
}
});
Thread t2
=new Thread(new Runnable() {
@Override
public void run() {
try {
test
.cal();
} catch (InterruptedException e
) {
}
}
});
t1
.start();sleep(1000);t2
.start();
sleep(1000);t2
.interrupt();
sleep(7000);
System
.out
.println(t2
.interrupted());
}
}
lockInterruptibly 等待锁时响应中断,抛出异常->lockInterruptibly()函数抛出异常->上锁失败or不排队
public void lockInterruptibly() throws InterruptedException
{
sync
.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg
)
throws InterruptedException
{
if (Thread
.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg
))
doAcquireInterruptibly(arg
);
}
private void doAcquireInterruptibly(int arg
)
throws InterruptedException
{
final Node node
= addWaiter(Node
.EXCLUSIVE
);
boolean failed
= true;
try {
for (;;) {
final Node p
= node
.predecessor();
if (p
== head
&& tryAcquire(arg
)) {
setHead(node
);
p
.next
= null
;
failed
= false;
return;
}
if (shouldParkAfterFailedAcquire(p
, node
) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed
)
cancelAcquire(node
);
}
}
锁是否可以绑定条件(挖坑 Condition还没看,也没用过)
tryLock(notfairSync的nonfairTryAcquire方法)可以解决一些用synchronized解决很繁琐的死锁问题
原问题: 原来解决方案: 使用tryLock解决:
非块结构的锁(粒度更细) (挖坑!!!啊啊啊啊啊啊让我死了算了)
公平锁的上锁
acquire(int arg) 【加锁】
ReentrantLock fairLock
=new ReentrantLock();
fairLock
.lock();
final void lock(){
acquire(1);
}
public final void acquire(int arg
){
if (!tryAcquire(arg
) &&
acquireQueued(addWaiter(Node
.EXCLUSIVE
), arg
))
selfInterrupt();
}
}
tryAcquire(int acquires) 【尝试加锁】
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;
}
hasQueuedPredecessors() 【队是否为空or是否重入】
public final boolean hasQueuedPredecessors() {
Node t
= tail
;
Node h
= head
;
Node s
;
return h
!= t
&&
((s
= h
.next
) == null
|| s
.thread
!= Thread
.currentThread());
}
acquireQueued(final Node node,int arg) 【排队(tryAcquire()/prak)】
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
;
failed
= false;
return interrupted
;
}
if (shouldParkAfterFailedAcquire(p
, node
) &&
parkAndCheckInterrupt())
interrupted
= true;
}
} finally {
if (failed
)
cancelAcquire(node
);
}
}
shouldParkAfterFailedAcquire(Node pred,Node node)/parkAndCheckInterrupt() 【是否应该自旋】
private static boolean shouldParkAfterFailedAcquire(Node pred
, Node node
) {
int ws
= pred
.waitStatus
;
if (ws
== Node
.SIGNAL
)
return true;
if (ws
> 0) {
do {
node
.prev
= pred
= pred
.prev
;
} while (pred
.waitStatus
> 0);
pred
.next
= node
;
} else {
compareAndSetWaitStatus(pred
, ws
, Node
.SIGNAL
);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport
.park(this);
return Thread
.interrupted();
}
addWaiter(Node mode)/enq(final Node node) 【添加节点到队列中】
private Node
addWaiter(Node mode
) {
Node node
= new Node(Thread
.currentThread(), mode
);
Node pred
= tail
;
if (pred
!= null
) {
node
.prev
= pred
;
if (compareAndSetTail(pred
, node
)) {
pred
.next
= node
;
return node
;
}
}
enq(node
);
return node
;
}
private Node
enq(final Node node
) {
for (;;) {
Node t
= tail
;
if (t
== null
) {
if (compareAndSetHead(new Node()))
tail
= head
;
} else {
node
.prev
= t
;
if (compareAndSetTail(t
, node
)) {
t
.next
= node
;
return t
;
}
}
}
}
总结上锁过程(挖坑 一总结就头疼)
公平锁的解锁
release(int arg) 【解锁】
fairLock
.unlock();
public void unlock() {
sync
.release(1);
}
public final boolean release(int arg
) {
if (tryRelease(arg
)) {
Node h
= head
;
if (h
!= null
&& h
.waitStatus
!= 0)
unparkSuccessor(h
);
return true;
}
return false;
}
trylease(int releases) 【尝试解锁,解到0就算成功】
protected final boolean tryRelease(int releases
) {
int c
= getState() - releases
;
if (Thread
.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free
= false;
if (c
== 0) {
free
= true;
setExclusiveOwnerThread(null
);
}
setState(c
);
return free
;
}
unparkSuccessor(Node node) 【将node下一节点线程唤醒】
private void unparkSuccessor(Node node
) {
int ws
= node
.waitStatus
;
if (ws
< 0)
compareAndSetWaitStatus(node
, ws
, 0);
Node s
= node
.next
;
if (s
== null
|| s
.waitStatus
> 0) {
s
= null
;
for (Node t
= tail
; t
!= null
&& t
!= node
; t
= t
.prev
)
if (t
.waitStatus
<= 0)
s
= t
;
}
if (s
!= null
)
LockSupport
.unpark(s
.thread
);
}
总结解锁过程(挖坑)
非公平锁
说一点比较重要的:
unparkSuccessor()先compareAndSetWaitStatus(node, ws, 0);然后LockSupport.unpark(s.thread);unpark下一个线程。 不公平锁可能在CAS-unpark之间上了锁,那第一个节点就被唤醒(其实唤醒是没用的),但是这样代码比较好实现吧,否则我也想不到该咋办(毕竟我这么菜),正好acquireQueued(),被唤醒之后也要继续for(;;)来tryAcquire来能拿到锁,拿不到的时候再继续park。这个实现挺好的,,
源码
ReentrantLock unfairLock
=new ReentrantLock();
unfairLock
.lock();
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread
.currentThread());
else
acquire(1);
}
public final void acquire(int arg
){
if (!tryAcquire(arg
) &&
acquireQueued(addWaiter(Node
.EXCLUSIVE
), arg
))
selfInterrupt();
}
}
protected final boolean tryAcquire(int acquires
) {
return 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)
throw new Error("Maximum lock count exceeded");
setState(nextc
);
return true;
}
return false;
}
与公平锁性能对比
我觉着这里是因为正在占用的线程释放锁后到第一个节点得到锁会有延迟:占用的将state改为0 -> unpark下一个线程(也就是第一个节点) -> 第一个线程tryAcquire来一遍CAS(改state)也setExclusiveOwnerThread(current),才会有延迟的。
应用场景(烦死了!不想写!这玩意儿咋这么多 好累挖坑)
🔗