您的位置:首页 > 编程语言 > Java开发

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

2016-11-22 23:26 387 查看
http://blog.csdn.net/binling/article/details/50419103 

最核心的东西:synchronization state,同步状态:指示当前线程是否可以proceed还是需要wait的状态。

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

[java] view
plain copy

class SpinLock {  

    // use thread itself as  synchronization state  

    private AtomicReference<Thread> owner = new AtomicReference<Thread>();   

    private int count = 0; // reentrant count of a thread, no need to be volatile  

    public void lock() {  

        Thread t = Thread.currentThread();  

        if (t == owner.get()) { // if re-enter, increment the count.  

            ++count;  

            return;  

        }  

        while (owner.compareAndSet(null, t)) {} //spin  

    }  

    public void unlock() {  

        Thread t = Thread.currentThread();  

        if (t == owner.get()) { //only the owner could do unlock;  

            if (count > 0) --count; // reentrant count not zero, just decrease the counter.  

            else {  

                owner.set(null);// compareAndSet is not need here, already checked  

            }  

        }  

    }  

}  

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

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

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

2 TicketLock

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

[java] view
plain copy

class TicketLock {  

    private AtomicInteger serviceNum = new AtomicInteger(0);  

    private AtomicInteger ticketNum = new AtomicInteger(0);  

    private static final ThreadLocal<Integer> myNum = new ThreadLocal<Integer>();  

    public void lock () {  

        myNum.set(ticketNum.getAndIncrement());  

        while (serviceNum.get() != myNum.get()) {};  

    }  

    public void unlock() {  

        serviceNum.compareAndSet(myNum.get(), myNum.get() + 1);  

    }  

}  

3 CLHLock 

CLH好处

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

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





[java] view
plain copy

public class CLHLock implements Lock {  

    AtomicReference<QNode> tail = new AtomicReference<QNode>(new QNode());  

    ThreadLocal<QNode> myPred;  

    ThreadLocal<QNode> myNode;  

  

    public CLHLock() {  

        tail = new AtomicReference<QNode>(new QNode());  

        myNode = new ThreadLocal<QNode>() {  

            protected QNode initialValue() {  

                return new QNode();  

            }  

        };  

        myPred = new ThreadLocal<QNode>() {  

            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());  

    }  

}     

4 阻塞锁的实现

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

[java] view
plain copy

package lock;  

  

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;  

import java.util.concurrent.locks.LockSupport;  

  

public class CLHLock1 {  

    public static class CLHNode {  

        private volatile Thread isLocked;  

    }  

  

    @SuppressWarnings("unused")  

    private volatile CLHNode tail;  

    private static final ThreadLocal<CLHNode> LOCAL   = new ThreadLocal<CLHNode>();  

    private static final AtomicReferenceFieldUpdater<CLHLock1, CLHNode> UPDATER =  

                                AtomicReferenceFieldUpdater.newUpdater(CLHLock1.class,  

                                                                       CLHNode.class, "tail");  

  

    public void lock() {  

        CLHNode node = new CLHNode();  

        LOCAL.set(node);  

        CLHNode preNode = UPDATER.getAndSet(this, node);  

        if (preNode != null) {  

            preNode.isLocked = Thread.currentThread();  

            LockSupport.park(this);  

            preNode = null;  

            LOCAL.set(node);  

        }  

    }  

  

    public void unlock() {  

        CLHNode node = LOCAL.get();  

        if (!UPDATER.compareAndSet(this, node, null)) {  

            System.out.println("unlock\t" + node.isLocked.getName());  

            LockSupport.unpark(node.isLocked);  

        }  

        node = null;  

    }  

}  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java
相关文章推荐