共性: 都是公平锁,先进先出,通过自旋轮询状态
区别: CLH锁持有前个节点状态并轮询,MCS持有后一个节点状态并轮询。
0,节点类 QNode
package com.test.learn;
public class LockNode {
/**
* 标志锁的状态
*/
volatile boolean locked = false;
/**
* 用于保存后个节点
*/
volatile LockNode next = null;
}
1,CLHLock
package com.test.learn;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class CLHLock implements Lock {
// 提供CAS方式修改地址引用
private AtomicReference<LockNode> tail;
// 保存前一个节点引用
private ThreadLocal<LockNode> myPre;
// 当前节点
private ThreadLocal<LockNode> myNode;
public CLHLock() {
tail = new AtomicReference<>(new LockNode());
myNode = ThreadLocal.withInitial(LockNode::new);
myPre = ThreadLocal.withInitial(() -> null);
}
@Override
public void lock() {
// L1.将自身节点状态标志为true(已上锁)
LockNode node = myNode.get();
node.locked = true;
// L2.获取前个节点
LockNode pre = tail.getAndSet(node);
myPre.set(pre);
while (pre.locked) {
// L3.自旋等待前个节点释放锁,即前一个节点执行unLock(U2处)
}
}
@Override
public void unlock() {
// 获取当前节点
LockNode qnode = myNode.get();
// 通过状态标志为锁已释放
qnode.locked = false;
// 回收前驱节点
myNode.set(myPre.get());
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO
}
@Override
public boolean tryLock() {
// TODO
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO
return false;
}
@Override
public Condition newCondition() {
// TODO
return null;
}
}
2,MCSLock
package com.test.learn;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class MCSLock implements Lock {
// 提供CAS方式修改地址引用
private AtomicReference<LockNode> tail;
// 保存当前节点
private ThreadLocal<LockNode> myNode;
public MCSLock() {
// tail和CLH有区别,初始值为null
tail = new AtomicReference<>();
myNode = ThreadLocal.withInitial(LockNode::new);
}
@Override
public void lock() {
LockNode qnode = myNode.get();
// L1,获取前节点
LockNode pre = tail.getAndSet(qnode);
// L2.不存在前一个节点则直接获取锁了,否则自旋前节点的状态
if (null != pre) {
qnode.locked = true;
// L3 设置后续节点
pre.next = qnode;
while (qnode.locked) {
// 自旋前节点的状态
}
}
}
@Override
public void unlock() {
LockNode qnode = myNode.get();
if (qnode.next == null) {
// 为什么需要CAS判断是否更新成功?因为多线程下可能新增了新的节点。
if (tail.compareAndSet(qnode, null)) {
return;
}
// 循环到等到next有值后退出,也即后一个节点执行L3之后
while (qnode.next == null) {
}
}
// 解锁时候主动更新后节点状态(和CLH的主要差距点)
qnode.next.locked = false;
qnode.next = null;
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO
}
@Override
public boolean tryLock() {
// TODO
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO
return false;
}
@Override
public Condition newCondition() {
// TODO
return null;
}
}
3, 使用
package com.test.learn;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;
public class LockMain {
private static final int THEAD_CNT = 10;
private static Lock getLock() {
// return new MCSLock();
return new CLHLock();
}
public static void main(String[] args) throws Exception {
CyclicBarrier cb = new CyclicBarrier(THEAD_CNT);
CountDownLatch latch = new CountDownLatch(THEAD_CNT);
Lock lock = getLock();
for (int i = 0; i < THEAD_CNT; i++) {
Thread th = new Thread(() -> {
try {
cb.await();
System.out.println(Thread.currentThread().getName());
lock.lock();
System.out.println(Thread.currentThread().getName() + " Got the Lock!");
Thread.sleep(100);
lock.unlock();
System.out.println(Thread.currentThread().getName() + " Released the Lock!");
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}, "Thread:" + i);
th.start();
}
long start = System.currentTimeMillis();
latch.await();
System.out.println("Duration:" + (System.currentTimeMillis() - start));
}
}