1、自旋鎖
自旋鎖是采用讓目前線程不停地的在循環體内執行實作的,當循環的條件被其他線程改變時 才能進入臨界區。如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
使用了CAS原子操作,lock函數将owner設定為目前線程,并且預測原來的值為空。unlock函數将owner設定為null,并且預測值為目前線程。
當有第二個線程調用lock操作時由于owner值不為空,導緻循環一直被執行,直至第一個線程調用unlock函數将owner設定為null,第二個線程才能進入臨界區。
由于自旋鎖隻是将目前線程不停地執行循環體,不進行線程狀态的改變,是以響應速度更快。但當線程數不停增加時,性能下降明顯,因為每個線程都需要執行,占用CPU時間。如果線程競争不激烈,并且保持鎖的時間段。适合使用自旋鎖。
注:該例子為非公平鎖,獲得鎖的先後順序,不會按照進入lock的先後順序進行。
在自旋鎖中 另有三種常見的鎖形式:TicketLock ,CLHlock 和MCSlock
二、阻塞鎖
阻塞鎖,與自旋鎖不同,改變了線程的運作狀态。
在JAVA環境中,線程Thread有如下幾個狀态:
1,建立狀态
2,就緒狀态
3,運作狀态
4,阻塞狀态
5,死亡狀态
阻塞鎖,可以說是讓線程進入阻塞狀态進行等待,當獲得相應的信号(喚醒,時間) 時,才可以進入線程的準備就緒狀态,準備就緒狀态的所有線程,通過競争,進入運作狀态。
JAVA中,能夠進入\退出、阻塞狀态或包含阻塞鎖的方法有
,synchronized
關鍵字(其中的重量鎖),ReentrantLock,Object.wait()\notify(),LockSupport.park()/unpart()(j.u.c經常使用)

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;
}
}

在這裡我們使用了LockSupport.unpark()的阻塞鎖。 該例子是将CLH鎖修改而成。
阻塞鎖的優勢在于,阻塞的線程不會占用cpu時間, 不會導緻 CPu占用率過高,但進入時間以及恢複時間都要比自旋鎖略慢。
在競争激烈的情況下 阻塞鎖的性能要明顯高于 自旋鎖。
理想的情況則是; 線上程競争不激烈的情況下,使用自旋鎖,競争激烈的情況下使用,阻塞鎖。