几种自旋锁SpinLock,TicketLock,CLHLock,以及可重入实现要点,非阻塞锁实现要点

来源:互联网 发布:数据采集器厂家 编辑:程序博客网 时间:2024/05/18 01:25
http://blog.csdn.net/binling/article/details/50419103 
最核心的东西:synchronization state,同步状态:指示当前线程是否可以proceed还是需要wait的状态。

1.普通SpinLock (支持可重入的版本)

[java] view plain copy
  1. class SpinLock {  
  2.     // use thread itself as  synchronization state  
  3.     private AtomicReference<Thread> owner = new AtomicReference<Thread>();   
  4.     private int count = 0// reentrant count of a thread, no need to be volatile  
  5.     public void lock() {  
  6.         Thread t = Thread.currentThread();  
  7.         if (t == owner.get()) { // if re-enter, increment the count.  
  8.             ++count;  
  9.             return;  
  10.         }  
  11.         while (owner.compareAndSet(null, t)) {} //spin  
  12.     }  
  13.     public void unlock() {  
  14.         Thread t = Thread.currentThread();  
  15.         if (t == owner.get()) { //only the owner could do unlock;  
  16.             if (count > 0) --count; // reentrant count not zero, just decrease the counter.  
  17.             else {  
  18.                 owner.set(null);// compareAndSet is not need here, already checked  
  19.             }  
  20.         }  
  21.     }  
  22. }  


为什么用Thread 本身当 同步状态而不是一个简单的boolean flag? 因为可以携带更多信息(当前owning thread)

1) 支持可重入,判断是否是重入,重入不需要改变同步状态,而只需要计数

2)确保只有锁的拥有者才能做unlock


2 TicketLock

思路:类似银行办业务,先取一个号,然后等待叫号叫到自己。好处:保证FIFO,先取号的肯定先进入。而普通的SpinLock,大家都在转圈,锁释放后谁刚好转到这谁进入。

[java] view plain copy
  1. class TicketLock {  
  2.     private AtomicInteger serviceNum = new AtomicInteger(0);  
  3.     private AtomicInteger ticketNum = new AtomicInteger(0);  
  4.     private static final ThreadLocal<Integer> myNum = new ThreadLocal<Integer>();  
  5.     public void lock () {  
  6.         myNum.set(ticketNum.getAndIncrement());  
  7.         while (serviceNum.get() != myNum.get()) {};  
  8.     }  
  9.     public void unlock() {  
  10.         serviceNum.compareAndSet(myNum.get(), myNum.get() + 1);  
  11.     }  
  12. }  

3 CLHLock 

CLH好处

1)公平,FIFO,先来后到的顺序进入锁

2)而且没有竞争同一个变量,因为每个线程只要等待自己的前继释放就好了。





[java] view plain copy
  1. public class CLHLock implements Lock {  
  2.     AtomicReference<QNode> tail = new AtomicReference<QNode>(new QNode());  
  3.     ThreadLocal<QNode> myPred;  
  4.     ThreadLocal<QNode> myNode;  
  5.   
  6.     public CLHLock() {  
  7.         tail = new AtomicReference<QNode>(new QNode());  
  8.         myNode = new ThreadLocal<QNode>() {  
  9.             protected QNode initialValue() {  
  10.                 return new QNode();  
  11.             }  
  12.         };  
  13.         myPred = new ThreadLocal<QNode>() {  
  14.             protected QNode initialValue() {  
  15.                 return null;  
  16.             }  
  17.         };  
  18.     }  
  19.   
  20.     @Override  
  21.     public void lock() {  
  22.         QNode qnode = myNode.get();  
  23.         qnode.locked = true;  
  24.         QNode pred = tail.getAndSet(qnode);  
  25.         myPred.set(pred);  
  26.         while (pred.locked) {  
  27.         }  
  28.     }  
  29.   
  30.     @Override  
  31.     public void unlock() {  
  32.         QNode qnode = myNode.get();  
  33.         qnode.locked = false;  
  34.         myNode.set(myPred.get());  
  35.     }  
  36. }     

4 阻塞锁的实现

CLH每个线程lock 的时候 spin on 它的前驱,不park,unlock的时候,只需要修改自身状态,不需要唤醒(unpark)后继线程。而阻塞方式下,lock的时候需要park自己,unlock的时候要 unpark后继

[java] view plain copy
  1. package lock;  
  2.   
  3. import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;  
  4. import java.util.concurrent.locks.LockSupport;  
  5.   
  6. public class CLHLock1 {  
  7.     public static class CLHNode {  
  8.         private volatile Thread isLocked;  
  9.     }  
  10.   
  11.     @SuppressWarnings("unused")  
  12.     private volatile CLHNode tail;  
  13.     private static final ThreadLocal<CLHNode> LOCAL   = new ThreadLocal<CLHNode>();  
  14.     private static final AtomicReferenceFieldUpdater<CLHLock1, CLHNode> UPDATER =  
  15.                                 AtomicReferenceFieldUpdater.newUpdater(CLHLock1.class,  
  16.                                                                        CLHNode.class"tail");  
  17.   
  18.     public void lock() {  
  19.         CLHNode node = new CLHNode();  
  20.         LOCAL.set(node);  
  21.         CLHNode preNode = UPDATER.getAndSet(this, node);  
  22.         if (preNode != null) {  
  23.             preNode.isLocked = Thread.currentThread();  
  24.             LockSupport.park(this);  
  25.             preNode = null;  
  26.             LOCAL.set(node);  
  27.         }  
  28.     }  
  29.   
  30.     public void unlock() {  
  31.         CLHNode node = LOCAL.get();  
  32.         if (!UPDATER.compareAndSet(this, node, null)) {  
  33.             System.out.println("unlock\t" + node.isLocked.getName());  
  34.             LockSupport.unpark(node.isLocked);  
  35.         }  
  36.         node = null;  
  37.     }  
  38. }  

0 0
原创粉丝点击