写锁
tryAcquire()
1. 在获取写锁时,会尝试判断当前对象是否拥有了锁(读锁与写锁),如果已经拥有且持有的线程并非当前线程,直接失败。
2. 如果当前对象没有被加锁,那么写锁就会为为当前对象上锁,并且将写锁的个数加1.
3. 将当前对象的排他锁线程持有者设为自己
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 写锁的上锁流程
*/
@Slf4j(topic = "enjoy")
public class RWLock2 {
//读写锁
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
w.lock();
try {
log.debug("t1 w---加锁成功");
} finally {
w.unlock();
}
}, "t1");
t1.start();
}
}
//写锁在加锁的时候要么锁没有被人持有则会成功,要么锁是重入 否则都失败
protected final boolean tryAcquire(int acquires) {
/*
*1、获取当前线程
*/
Thread current = Thread.currentThread();
//获取锁的状态----默认是0
int c = getState();
//因为读写锁是同一把锁(同一个对象),所以为了表示读写锁,把锁的前16位表示读锁的状态 后16位表示写锁的状态
//获取写锁的状态
int w = exclusiveCount(c);
//表示有人上了锁(maybe w or r)
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
/*
* 1、判断当前锁是什么锁。如果是只有读锁直接加锁失败
* 为什么呢?因为w==0 标识这把锁从来没有上过写锁,只能是读锁
* 而当前自己是来上写锁的所以只能是升级 故而失败
* 2、如果需要进到第二个判断|| 标识第一个失败了也就是这把锁有可能上了写锁 也有可能上了读写锁
* 判断是否重入 如果不是重入失败
*/
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//重入 把w+1 长度有限 但是这个判断基本没用
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
//没用超出重入的最大限制 则把w+1
setState(c + acquires);
return true;
}
//writerShouldBlock 自己要不要排队
//如果正常情况下就是当前这个例子第一次加锁
//writerShouldBlock 判断队列当中是有有人排队 如果有人排队 如果是公平锁则自己去排队 非公平锁则不排队
//如果是非公平则不管有没有人排队直接抢锁
//公平 如果队列当中没人 则不需要排队则(writerShouldBlock()=false) 加锁
//公平 如果队列当中有人 则需要排队则(writerShouldBlock()=true) 加锁 会执行 if快当中的reture false 标识加锁失败
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires)){
return false;
}
//加锁成功则把当前持有锁的线程设置自己
setExclusiveOwnerThread(current);
return true;
}