版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22271479/article/details/85035196
重入锁(ReentrantLock)
含义
重入锁,标识在一个线程中,可重复对该资源重复加锁。
- synchronized就是重入锁
- ReentrantLock也支持冲入操作
- 是排它锁(独占锁)
针对于AQS实现重入功能
在重写tryAquiresxxx的时候考虑同一个线程多次lock的情况即可
伪代码
- aquire方法
Thread currentThread = Thread.currentThread();
//getExclusiveOwnerThread() 标识独占模式下的当前线程对象引用
if(currentThread == getExclusiveOwnerThread())
- release方法
- 这里,就是当前线程获取了多次
- 比如1.lock() 2.lock() 3.unlock() 4.unlock
- 这里ReentrantLock的aquire()方法传入的是1
- 执行1,2后state分别是 1,2
- 执行3 c = 2-1 //setState(2-1)
- 执行4 c = 1-1 //直接释放
protected final boolean tryRelease(int releases) {
//同一个线程多次获取资源锁的话,state会累加,那么这里做累减操作
int c = getState() - releases;
//不是当前线程去release的话,抛出monitor异常,当然并不是monitor底层实现的
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//c == 0的话,就表示不存在一个线程获取多次,那么直接release
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
//这里,就是当前线程获取了多次
//比如1.lock() 2.lock() 3.unlock() 4.unlock
//这里ReentrantLock的aquire()方法传入的是1
//执行1,2后state分别是 1,2
//执行3 c = 2-1 //setState(2-1)
//执行4 c = 1-1 //直接释放
setState(c);
return free;
}
公平锁和非公平锁
- AQS 默认没有处理锁的公平争夺策略,获取锁的逻辑是需要用户自行定义
- ReentrantLock实现了公平和非公平
- 多线程下,线程去获取锁的顺序是不固定的
- 公平锁比非公平锁性能要低(需要拒绝获取,直到该线程是head的时候才会成功获得资源锁)
Node链表 head–>N1(pre,next)–>N2(pre,next)<–tail
//true 标识在队列中的该线程拥有前置节点
//false 该线程是head或者 null==null即空队列 tail==head==null
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//非公平锁 没有hasQueuedPredecessors()方法
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;
}
公平锁最终获得锁的顺序和队列中的顺序是一致的,FIFO
公平与非公平性能
- 公平锁能保证FIFO规则,但是增加了线程切换的次数
为什么?
AQS操作虽然使用CAS无锁操作机制,但是,CPU在调度的时候,切换至该线程的时候,该线程去获取该资源锁,但是FIFO原则,无法获取锁,将处于自旋操作,后续线程任务无法执行,cpu调度结束,就切换至下一个线程。
公平锁大大的增加了CPU线程调度次数,导致吞吐率(TPS)降低
- 非公平锁,只要该线程获得到CPU时间片,那么在没有线程获取锁的时候,就可以得到锁,执行任务,减少了线程切换,提高了TPS。
使用
/**
* describe:
* E-mail:[email protected] date:2018/12/16
*
* @Since 0.0.1
*/
public class ReentRantLockTest {
//默认构造是非公平
//true是公平锁
//false是非公平锁
public static final Lock lock = new ReentrantLock(true);
static class T extends Thread {
public T(String name){
super(name);
}
@Override
public void run() {
lock.lock();
System.out.println("==" + Thread.currentThread().getName());
try {
//Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
test.T t = new test.T(String.valueOf(i+"Thread"));
t.start();
}
System.out.println(null == null);
}
}
不公平锁
公平锁