JAVAロック---------CLHロックとMCSロック


参考:http://ifeve.com/java_ロックsee 2/
一:CLHロック
  • 実装
    package com.eden.coreLearn.thread.lock;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
    
    import org.junit.Test;
    
    /**
     * CLH   
     * 
     * @author [email protected] 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 nodeLocal = new ThreadLocal();
    
        //    CLHLock       tail,   CLHNode      (      volatile     )
        private static final AtomicReferenceFieldUpdater 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ノードを新たに作成し、自分のスレッドスタックに共存して、共有のtail nodeをudaterで取得し、共有の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 [email protected] 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 nodeLocal = new ThreadLocal();
        
        @SuppressWarnings("unused")
        private volatile MCSNode node;
        
        private static final AtomicReferenceFieldUpdater 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の問題は存在しません。