事前に考える
まず、ReentrantLockと同期の最大の違いは、同期がオブジェクトのヘッドをロックすることであり、ReentrantLockはロックの購入に似ており、マルチスレッドによるリソースの原子性と可視性の問題を引き起こさないことを明確にします。この点を明らかにすると、実際のロックは実際のロックとそれほど変わりません。実際のロックはドアのロックにすぎないので、上記のロックがここにあることを他のユーザーに伝えます。唯一の違いは、プログラムロックはロックをロックした人はロックを解除し、実際には他の誰かのロックを保持してロックを解除できます。
主に使用されているクラス
- AtomicInteger:主に、このロックの原子性と可視性、および後続の再入可能ロックの状態を保証します。注:揮発性は、リソースの可視性のみを保証できますが、原子性は保証できません
- スレッド:現在のスレッドがロックを保持している[PS:誰がロックを保持しているか、再入可能なロックはここから後で再入力でき、ロック解除に必要なもの]
- LinkedBlockingQueue:ロックオブジェクトを取得しなかったコンテナ
- LockSupport:スレッド状態の切り替え
説明が終わりました!!!!
/**
* 线程状态定义
*/
AtomicInteger state = new AtomicInteger();
/**
* 那个线程持有锁
*/
Thread ownerThread = null;
/**
* 存放线程的容器
*/
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();
このステップは続行するために言うことは何もありません!!
public boolean tryLock() {
//不用每次都进行CAS操作,如果当期状态为0我直接返回抢锁成功
if (state.get() == 0) {
//CAS抢锁
if (state.compareAndSet(0, 1)) {
//将抢到锁的线程设定为当前锁的持有者
ownerThread = Thread.currentThread();
return true;
}
} else if (ownerThread == Thread.currentThread()) {
System.out.println("重入锁成功!!!!");
state.set(state.get() + 1);
return true;
}
return false;
}
ここではCASメカニズムが主に使用されます。変更が成功すると、ロックが取得されたことを証明します。失敗すると、キューに追加されます。再入可能ロックが現在のスレッドである場合、ロックは正常に取得され、状態+1 [PS:ここでの状態+1は主に再入可能ロックになるためには、再入可能ロックの性質上、数回ロックして数回解放する必要があります]
public void lock() {
//真公平锁 如果没有!waiters.isEmpty(),在锁的上一个持有者他也会抢
if (!waiters.isEmpty() || !tryLock()) {
//没抢到锁进入等待队列
waiters.add(Thread.currentThread());
for (; ; ) {
if (tryLock()) {
//移除并且返回队列头部
waiters.poll();
return;
} else {
//没抢到 进入阻塞(WAITING)
LockSupport.park();
}
}
}
}
ロックを保持しているスレッドがない場合は、直接戻ります。ある場合は、キューに追加してブロックします[PS:もちろん、一部の類人猿は、LinkedBlockingQueueの使用はすでに公平なロック(先入れ先出し)であると考えていますが、実際には、3つのスレッドがあり、 1人がロックの獲得に成功しました。解放後、1人もロックの獲得に参加しました。つまり、ラインにジャンプします!!ここでキューをジャンプすると、一見公平なロックが不公平になります]
public void unlock() {
//如果不是当前线程那么不允许释放锁
if (Thread.currentThread() != ownerThread) {
throw new RuntimeException("不是你的别乱动,你不是锁的持有者");
}
//释放锁的过程,每次过来减一
if (state.decrementAndGet() == 0) {
ownerThread = null;
//获取第一个等待的元素并且通知他开始抢锁了,此时还不能移除
//在真正抢到锁后才能移除队列
Thread waiter = waiters.peek();
if (waiter != null) {
LockSupport.unpark(waiter);
}
}
}
ここで、ロックを解放するときは、現在ロックを保持しているスレッドでなければなりません。他のスレッドがロックを解放すると、
PS がめちゃくちゃになります。何か問題がある場合は、遠慮なく指摘してください