来自https://www.bilibili.com/video/BV1ta4y1H73X?from=search&seid=4946324253512830264
ReehtrahtLock是可重入的意思
表示一个线程如果持有锁A,那么在调用该线程子程序的时候,可以再次重入这个锁(state + 1),不过锁的释放也需要多释放一次
非公平获取锁
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; //是则重入,给state加上acquires(一般为1)
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;
if (c == 0) { // 所有锁已经被释放,才会返回true
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;//如果还有其他子程序在占有锁,仍然返回false
}
非公平锁实现的方法
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平锁的实现方法
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
/**下面这个就是重入锁的原理,如果锁属于当前线程,那么可以继续累加state*/
else if (current == getExclusiveOwnerThread()) {// 锁是否属于当前线程
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
Reentrantlock一部分是在jdk级别解决锁问题的,还有一部分会使用os的系统调用,比如park,系统调用是很耗资源的,所以我的理解 轻量级锁和重量级锁的区别,就是轻量级锁是基于jdk的,而重量级锁,是会涉及到系统调用的
并发不见得是竞争的,线程排队示意图如下:
1.6之前reentrantlock性能优于sychronized,但是1.6之后两者性能没有啥区别,不过reentrantlock的API比较丰富多样,比如condition lock条件锁
lock AQS {
自旋
park-unpark
CAS
}
自旋和cas不是一回事儿,只是再cas的时候可以利用自旋机制来不断重试
自旋是一种锁优化机制,所以锁优化中会有『自旋锁』的概念(线程空转重试获取锁),自旋不一定是用在cas场景,其他锁场景也是能用的(比如互斥锁)
不同线程-- 如果没有共享资源的冲突,其实不会导致AQS队列入队操作--jdk级别解决同步问题
Node类大体设计如下,包含 prev,next,以及当前线程Thread
public class Node {
Node prev;
Node next;
Thread thread;
}
队列的队头的Node里面,Thread的值永远都为空,结构大致如下(Thread左边到Thread右边少了一个next到prev的箭头)