java各种锁

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

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

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,大家都在转圈,锁释放后谁刚好转到这谁进入。

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)而且没有竞争同一个变量,因为每个线程只要等待自己的前继释放就好了。





public class CLHLock implements Lock {
	AtomicReference<QNode> tail = new AtomicReference<QNode>(new QNode());
	ThreadLocal<QNode> myPred;
	ThreadLocal<QNode> myNode;
public CLHLock() {
	tail = new AtomicReference&lt;QNode&gt;(new QNode());
	myNode = new ThreadLocal&lt;QNode&gt;() {
		protected QNode initialValue() {
			return new QNode();
		}
	};
	myPred = new ThreadLocal&lt;QNode&gt;() {
		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后继

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&lt;CLHNode&gt; LOCAL   = new ThreadLocal&lt;CLHNode&gt;();
private static final AtomicReferenceFieldUpdater&lt;CLHLock1, CLHNode&gt; 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;
}

}



猜你喜欢

转载自blog.csdn.net/huanchankuang3257/article/details/82951863