分享

CLH锁学习

 知识存储馆 2013-06-20

CLH锁即Craig, Landin, and Hagersten (CLH) locks,CLH锁是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。
何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

CLHLock的java实现逻辑:

 

Java代码  收藏代码
  1. public class CLHLock implements Lock {  
  2.     private final AtomicReference tail;  
  3.     private final ThreadLocal myPred;  
  4.     private final ThreadLocal myNode;  
  5.   
  6.     public CLHLock() {  
  7.         tail = new AtomicReference(new QNode());  
  8.         myNode = new ThreadLocal() {  
  9.             protected QNode initialValue() {  
  10.                 return new QNode();  
  11.             }  
  12.         };  
  13.   
  14.         myPred = new ThreadLocal();  
  15.     }  
  16.   
  17.     @Override  
  18.     public void lock() {  
  19.         QNode node = myNode.get();  
  20.         node.locked = true;  
  21.         QNode pred = tail.getAndSet(node);  
  22.         myPred.set(pred);  
  23.         while (pred.locked) {  
  24.         }  
  25.     }  
  26.   
  27.     @Override  
  28.     public void unlock() {  
  29.         QNode node = myNode.get();  
  30.         node.locked = false;  
  31.         myNode.set(myPred.get());  
  32.     }  
  33.   
  34.     private static class QNode {  
  35.         volatile boolean locked;  
  36.     }  
  37. }  
 


锁本身被表示成QNode的虚拟链表。共享的tail保存申请的最后的一个申请lock的线程的myNode域。每个申请lock的线程通过一个本地线程变量pred指向它的前驱。另外一个本地线程变量myNode的locked保存本身的状态,true:正在申请锁或已申请到锁;false:已释放锁。每个线程通过监视自身的前驱状态,自旋等待锁被释放。释放锁时,把自身myNode的locked设为false,使后继线程获的锁,并回收前驱的QNode,等待下次使用,因为自身的QNode可能被tail获后继引用,而前驱不再使用老的QNode。

AbstractQueuedSynchronizer的实现也是部分基于"CLH"队列的思想。具体见AbstractQueuedSynchronizer的doAcquireSharedInterruptibly方法实现
AbstractQueuedSynchronizer 为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁定和相关同步器(信号量、事件,等等)提供一个框架。用java的人都知道synchronized能够对一个需要确保线程安全的对象,方法实现多线程并发控制,这是在java语法层次的实现,而AbstractQueuedSynchronizer 则是在应用层次而不是语法层次(更高的层次)提供了实现多线程并发控制组件的基础。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多