参考:http://ifeve.com/java_lock_see2/
一:CLH锁
- 实现
package com.eden.coreLearn.thread.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.junit.Test; /** * CLH自旋锁 * * @author eden.ding1991@gmail.com 2016年7月15日 下午5:39:38 */ public class CLHLock { public static class CLHNode { private volatile boolean isLocked = true; } @SuppressWarnings("unused") private volatile CLHNode tail; private static final ThreadLocal<CLHNode> nodeLocal = new ThreadLocal<CLHNode>(); //构建一个CLHLock对象中变量名为tail,类型为CLHNode的原子更新器(该变量必须有volatile关键字修饰) private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> updater = AtomicReferenceFieldUpdater .newUpdater(CLHLock.class, CLHNode.class, "tail"); public void lock() { CLHNode node = new CLHNode(); nodeLocal.set(node); CLHNode preNode = updater.getAndSet(this, node); // System.out.println(String.format("preNode=%s", preNode)); if (preNode != null) { while (preNode.isLocked) { } preNode = null; nodeLocal.set(node);//没看懂为什么又要set一次 } } public void unlock() { CLHNode node = nodeLocal.get();//获取当前线程锁的节点 if (!updater.compareAndSet(this, node, null)) { node.isLocked = false; } node = null; } @Test public void testCLHLock() throws InterruptedException { Student st = new Student(new CLHLock()); for (int i = 0; i < 100; i++) { new Thread(new CLHLockThread(st), i + "").start(); } TimeUnit.SECONDS.sleep(30); } public class Student { private int i = 0; private CLHLock lock; public Student(CLHLock lock) { this.lock = lock; } public void add() { lock.lock(); this.i = this.i + 1; System.out.println(String.format("线程%s的变量i=%s", Thread.currentThread().getName(), this.i)); // lock.unlock(); } } public class CLHLockThread extends Thread { private Student st; public CLHLockThread(Student st) { this.st = st; } @Override public void run() { st.add(); } } }
- CLH锁是通过不停的查询前驱变量preNode来实现的,是隐式的队列,并没有真实的后继节点
- lock函数实现:调用lock的时候,先新建一个自己的tail node节点,并存到自己的线程栈里,然后通过updater获取共享的tail node并将共享的tail node更新成自己的tail node,如果共享的tail node不为空,则获取锁失败,执行空轮询,反之成功
- unlock函数实现,先取出当前线程的tail node节点,并与共享的tail node节点比较,如果相同,则释放锁,同时将共享的tail node更新成null
- CLH锁也是公平锁,遵循先来后到的顺序,但是和其他自旋锁一样,竞争激烈时会导致性能下降
二:MCS锁
- 实现
package com.eden.coreLearn.thread.lock; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * * @author eden.ding1991@gmail.com 2016年7月15日 下午6:36:40 */ public class MCSLock { public class MCSNode { private volatile MCSNode next; private volatile boolean isLocked = true; } private static final ThreadLocal<MCSNode> nodeLocal = new ThreadLocal<MCSNode>(); @SuppressWarnings("unused") private volatile MCSNode node; private static final AtomicReferenceFieldUpdater<MCSLock, MCSNode> updater = AtomicReferenceFieldUpdater .newUpdater(MCSLock.class, MCSNode.class, "node"); public void lock() { MCSNode current = new MCSNode(); nodeLocal.set(current); MCSNode preNode = updater.getAndSet(this, current); if (preNode != null) { preNode.next = current; while (current.isLocked) { } } } public void unlock() { MCSNode current = nodeLocal.get(); if (current.next == null) { if (updater.compareAndSet(this, current, null)) { } else { while (current.next == null) { } } } else { current.next.isLocked = false; current.next = null; } } }
- 实现其实再CLH锁的基础上加了真实的后继节点
- CLHlock是不停的查询前驱变量, 导致不适合在NUMA 架构下使用(在这种结构下,每个线程分布在不同的物理内存区域,MCSLock则是对本地变量的节点进行循环。不存在CLHlock 的问题。