锁是用来解决多线程并发访问共享资源所带来的的数据安全性问题的手段。对一个共享资源加锁后,如果有一个线程获得了锁,那么其他线程无法访问这个共享资源。
一个持有锁的线程再释放锁之前,如果再次访问了该同步锁的其他方法,这个线程不需要再次争抢锁,只需要记录重入的次数。
public class Main {
static Lock lock = new ReentrantLock(); // 重入锁
static int count = 0;
static void incr() { // 递增
lock.lock();
count++;
/*
* 但是这是重入锁 线程A 已经获得了该重入锁 调用方法内
* 再次请求增强锁不会导致死锁 只会记录重入的次数
* 所以重入锁可以解决死锁的问题
*/ decr();
lock.unlock();
}
static void decr() { // 递减
/* 又需要增强锁 线程A 要等 线程A 释放锁,发生死锁 */ lock.lock();
count--;
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++) {
new Thread(Main::incr).start();
}
Thread.sleep(3000);
System.out.println("result : " + count);
}
}
问题思考:锁是如何实现线程的阻塞以及唤醒的?互斥的逻辑是怎么实现的?
// jdk 17
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
@ReservedStackAccess
final void lock() {
if (!initialTryLock())
acquire(1);
}
}
// 非公平锁
static final class NonfairSync extends Sync {
final boolean initialTryLock() {
Thread current = Thread.currentThread();
// CAS 操作修改 state (互斥变量 0 表示无锁 > 0 表示有锁)
// 本质是乐观锁 预期值为 0 时修改为 1
if (compareAndSetState(0, 1)) {
// 设置当前线程为独占状态
setExclusiveOwnerThread(current);
return true;
} else if (getExclusiveOwnerThread() == current) {
int c = getState() + 1;
if (c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
} else
return false;
}
// 尝试抢占锁
protected final boolean tryAcquire(int acquires) {
// 判断 state 占用状态和 CAS 结果
if (getState() == 0 && compareAndSetState(0, acquires)) {
// 设置当前线程为独占状态
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}
// 公平锁
static final class FairSync extends Sync {...}
public ReentrantLock() {
// 构造的时候默认构造了一个非公平锁
sync = new NonfairSync();
}
public void lock() {
// lock.lock()
sync.lock();
}
public final void acquire(int arg) {
// 尝试抢占锁 arg 抢占的数量
if (!tryAcquire(arg))
// AQS
acquire(null, arg, false, false, false, 0L);
}
initialTryLock()
方法在公平锁和非公平锁中均有实现,公平锁意味着已经获得了锁的线程释放了锁那么应该从等待的线程中去唤醒一个线程去访问,非公平锁意味着在等待的线程中突然出现了一个新的线程来抢占锁是有可能被抢占走的。
abstract static class Sync extends AbstractQueuedSynchronizer {
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
boolean free = (c == 0); // 表示可以释放锁
if (free)
// 设置为 null 后完成锁的释放
setExclusiveOwnerThread(null);
setState(c);
return free;
}
}
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
signalNext(head);
return true;
}
return false;
}
private static void signalNext(Node h) {
Node s;
// 这里通过 GC 回收
if (h != null && (s = h.next) != null && s.status != 0) {
s.getAndUnsetStatus(WAITING);
// 在这里完成锁的释放
LockSupport.unpark(s.waiter);
}
}