博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
我理解的CLH
阅读量:5926 次
发布时间:2019-06-19

本文共 4145 字,大约阅读时间需要 13 分钟。

学而时习之,不亦说乎!

                             --《论语》

原创,转载请附原文链接,谢谢。

CLH

思路

  • 保持时序的锁基本思路就是将等待获取锁的线程放入集合,锁释放后,等待线程之一获取到锁。

问题

  • 如何排队?

    • CLH使用反向链表的形式进行排队。也就是后继节点主动询问,而不是前继节点主动通知。
  • 排队是否公平?

    • CLH是公平锁。即后申请获取锁的排在队列末尾。
  • 如何唤醒?

    • CLH通过每个线程自旋。每个等待线程通过不断自旋前继节点状态判断是否能获取到锁。

实现

  • CLH排队使用公平方式,锁内部需要保存【尾节点】的引用,每次排队线程加入到队列最末尾。
  • CLH锁使用反向链表方式进行排队,那么每个线程就需要维护【自己的状态】和保持一个【前向节点的引用】。
  • CLH使用一个【boolean值】表示当前线程获取锁状态。false表示当前线程释放锁;true表示当前线程等待获取锁或已经获取到锁。

代码

Lock.java

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
public interface Lock {
   void lock();
   void unlock();
}
 
 

CLHLock.java

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
import java.util.concurrent.atomic.AtomicReference;
public class CLHLock implements Lock {
   private final AtomicReference
tail;
   private final ThreadLocal
myPred;
   private final ThreadLocal
myNode;
   public CLHLock() {
       tail = new AtomicReference
(new QNode());
       myNode = new ThreadLocal
() {
           @Override
           protected QNode initialValue() {
               return new QNode();
           }
       };
       myPred = new ThreadLocal
() {
           @Override
           protected QNode initialValue() {
               return null;
           }
       };
   }
   @Override
   public void lock() {
       QNode qnode = myNode.get();
       qnode.locked = true;
       QNode pred = tail.getAndSet(qnode);
       myPred.set(pred);
       while (pred.locked) {
       }
   }
   @Override
   public void unlock() {
       QNode qnode = myNode.get();
       qnode.locked = false;
       // myNode.set(myPred.get());这一行是否有必要???
   }
   private static class QNode {
       public volatile boolean locked;
   }
}
 
 

测试

 
 
 
xxxxxxxxxx
 
 
 
 
package com.zby.clh;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CLHMain {
   private Lock lock = new CLHLock();
   public void say(String msg) {
       System.out.println(Thread.currentThread().getName() + " : 尝试获取锁");
       lock.lock();
       System.out.println(Thread.currentThread().getName() + " : 获取到锁");
       try {
           System.out.println(Thread.currentThread().getName() + msg + "?");
           TimeUnit.SECONDS.sleep(1);
           System.out.println(Thread.currentThread().getName() + msg + "!");
           TimeUnit.SECONDS.sleep(1);
           System.out.println(Thread.currentThread().getName() + msg + ".");
           TimeUnit.SECONDS.sleep(1);
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           lock.unlock();
           System.out.println(Thread.currentThread().getName() + " : 释放锁");
       }
   }
   public static void main(String[] args) throws Exception {
       String msg = "Hello,World";
       CLHMain clhMain = new CLHMain();
       ExecutorService executorService = Executors.newCachedThreadPool();
       for (int i = 0; i < 5; i++) {
           executorService.submit(new Runnable() {
               @Override
               public void run() {
                   clhMain.say(msg);
               }
           });
       }
       executorService.awaitTermination(20, TimeUnit.SECONDS);
   }
}
 
 

结果

 
 
 
xxxxxxxxxx
 
 
 
 
pool-1-thread-1 : 尝试获取锁
pool-1-thread-2 : 尝试获取锁
pool-1-thread-1 : 获取到锁
pool-1-thread-1Hello,World?
pool-1-thread-3 : 尝试获取锁
pool-1-thread-4 : 尝试获取锁
pool-1-thread-5 : 尝试获取锁
pool-1-thread-1Hello,World!
pool-1-thread-1Hello,World.
pool-1-thread-1 : 释放锁
pool-1-thread-2 : 获取到锁
pool-1-thread-2Hello,World?
pool-1-thread-2Hello,World!
pool-1-thread-2Hello,World.
pool-1-thread-2 : 释放锁
pool-1-thread-3 : 获取到锁
pool-1-thread-3Hello,World?
pool-1-thread-3Hello,World!
pool-1-thread-3Hello,World.
pool-1-thread-3 : 释放锁
pool-1-thread-4 : 获取到锁
pool-1-thread-4Hello,World?
pool-1-thread-4Hello,World!
pool-1-thread-4Hello,World.
pool-1-thread-4 : 释放锁
pool-1-thread-5 : 获取到锁
pool-1-thread-5Hello,World?
pool-1-thread-5Hello,World!
pool-1-thread-5Hello,World.
pool-1-thread-5 : 释放锁
 
 

 

转载于:https://www.cnblogs.com/zby9527/p/10815563.html

你可能感兴趣的文章
FirewallD is not running
查看>>
linux ubuntu deepin apache2 rewrite
查看>>
如何像Uber一样给工程师派单,解放外包生产力?
查看>>
源码免杀处理的技巧与tips
查看>>
Groove list操作-转数组,collect,each等
查看>>
spring boot微服务通用部署启动脚本
查看>>
Word打不开,如何修复word文档?
查看>>
开发们 点广告-赚点BT币
查看>>
The import com.sun.tools cannot be resolved
查看>>
CSS Id 和 Class
查看>>
String,StringBuffer与StringBuilder的区别
查看>>
使用WebSocket绕过广告屏蔽插件
查看>>
WebService学习笔记---CXF入门
查看>>
10 个有关 String 的面试问题
查看>>
wireshark远程抓包
查看>>
Netty 4.x – ByteBuf
查看>>
JavaScript 开发的45个经典技巧
查看>>
【转】缅怀红薯精神
查看>>
Android开发入门之学习笔记(三):程序窗口的布局
查看>>
springMVC带文件的表单数据无法绑定到参数中
查看>>