Lock
ReentrantLock
public class ReentrantLockDemo {
static Lock lock = new ReentrantLock();
private static int count = 0;
private static void inc(){
// lock.lock();//抢占锁、如果没有抢占到锁,会阻塞
if (lock.tryLock()){//如果没有抢占到锁,这里不会阻塞
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// lock.unlock();
}
count ++;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++) {
new Thread(() ->{
ReentrantLockDemo.inc();
}).start();
}
Thread.sleep(3000);
System.out.println("result:"+count);
}
}
result:982
由于不是原子性,因此多线程相加会导致错误。
加上Lock
lock.lock();//抢占锁、如果没有抢占到锁,会阻塞
... ...
finally {lock.unlock();}
result:1000
由于加了锁,因此数据正常
ReentrantLock的实现原理
锁的特性:满足互斥性、意味着同一个时刻,只允许一个线程进入到加锁的代码中,在多线程环境下,可以让线程顺序访问
锁的设计猜想
- 一定会涉及到锁的抢占,需要有一个标记来实现互斥,全局变量(0、1)
- 抢占到了锁,怎么处理
- 未抢占到锁,怎么处理
- 需要等待(让处于排队中的线程,如果没有抢占到锁,则直接先阻塞,然后释放cpu资源)
如何等待?->wait/notify(线程通信的机制,无法指定唤醒某一个线程) LockSupport.park/unpark(阻塞一个制定的线程,唤醒一个指定的线程) condition
- 需要排队(允许有N个线程被阻塞,此时线程处于活跃状态)
- 抢占到锁的释放过程,怎么处理
- LockSupport.unpark-->唤醒处于队列中的指定线程
- 锁抢占的公平性(是否允许插队)
- 公平
- 非公平(synchronized)
AbstractQueuedsynchronizer(AQS)
Lock核心的机制在这里面做,提供了2种机制
- 共享锁
- 互斥锁
公平锁
ReentrantLock:
final void lock() {
acquire(1);//抢占一把锁
}
AbstractQueuedsynchronizer:
public final void acquire(int arg) {-->AQS里的方法
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
ReentrantLock:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {//无锁状态
if (!hasQueuedPredecessors() && //是否存在一个处理的队列
compareAndSetState(0, acquires)) { //cas操作-->(lock指令,cpu加锁):只有当前不存在队列的情况下才会cas
setExclusiveOwnerThread(current);//把获得锁的线程保存到ExclusiveOwnerThread中
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//如果当前获得锁的线程和当前占用锁的线程是同一个,表示重入锁,不需要cas操作
int nextc = c + acquires;//增加重入次数
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);//保存state
return true;
}
return false;
}
公平锁
ReentrantLock:
final void lock() {
if (compareAndSetState(0, 1))//不管当前AQS队列中是否有排队的情况,先去插队
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
AbstractQueuedsynchronizer:
public final void acquire(int arg) {-->AQS
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
ReentrantLock:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
ReentrantLock:
final boolean nonfairTryAcquire(int acquires) {-->非公平
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {//不去判断hasQueuedPredecessors
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
加入队列并且进行自旋等待
如果没有抢占到锁,则加入队列进行自旋等待
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
addWaiter(Node.EXCLUSIVE)---》添加一个互斥锁的节点
acquireQueued()---》自旋锁和阻塞的操作
addWaiter()
private Node addWaiter(Node mode) {
// 把当前线程封装成Node节点
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
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) { // Must initialize
if (compareAndSetHead(new Node()))//初始化head节点
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}