几种自旋锁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;
}
}
最核心的东西: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;
}
}
相关文章推荐
- 几种自旋锁SpinLock,TicketLock,CLHLock,以及可重入实现要点,非阻塞锁实现要点
- linux中大内核锁(BKL--Big Kernel Lock)和自旋锁(FIFO Ticket Spinlock) -- 2014百度面试题目
- (六)线程--分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥)(示例下载)
- MSP430FG439上实现IO模拟UART以及移植要点解析
- 嵌入式 自旋锁(spinlock)详解以及使用示例
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
- 9.11 给定一个布尔表达式,由0、1、&、|、^等符号组成,以及一个想要的布尔结果result,实现一个函数,算出有几种括号的放法可使该表达式得出result的值。
- (六)线程--分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥)(示例下载)
- 聊聊高并发(七)实现几种自旋锁(二)
- pv ticketlock解决虚拟环境下的spinlock问题
- pv ticketlock解决虚拟环境下的spinlock问题
- 通过Lock对象以及Condition对象实现多线程同步
- MSP430FG439上实现IO模拟UART以及移植要点解析
- 字符、字节、编码的概念解析和程序实现以及几种误解解惑
- Qt4.8.2 QPushButton按钮贴图以及实现按钮的几种常用状态
- 高性能自旋锁 MCS Spinlock 的设计与实现
- 堆栈以及常用的几种堆栈实现原理
- Silverlight 2.0使用Lock, Interlocked, EventWaitHandle, Monitor来实现线程同步//C#线程同步的几种方法
- 几种所的实现 自旋所,排队自旋锁,MCS锁,CLH锁
- 聊聊高并发(六)实现几种自旋锁(一)