485
汽車大全
Java鎖的種類以及辨析(二):自旋鎖的其他種類
鎖作為並發共享數據,保證一致性的工具,在JAVA平台有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本係列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。
2.自旋鎖的其他種類
上篇我們講到了自旋鎖,在自旋鎖中 另有三種常見的鎖形式:TicketLock ,CLHlock 和MCSlock
Ticket鎖主要解決的是訪問順序的問題,主要的問題是在多核cpu上
01 |
package com.alipay.titan.dcc.dal.entity;
|
03 |
import java.util.concurrent.atomic.AtomicInteger;
|
05 |
public class TicketLock {
|
06 |
private AtomicInteger serviceNum = new AtomicInteger();
|
07 |
private AtomicInteger ticketNum = new AtomicInteger();
|
08 |
private static final ThreadLocal<Integer> LOCAL = new ThreadLocal<Integer>();
|
11 |
int myticket = ticketNum.getAndIncrement();
|
13 |
while (myticket != serviceNum.get()) {
|
18 |
public void unlock() {
|
19 |
int myticket = LOCAL.get();
|
20 |
serviceNum.compareAndSet(myticket, myticket + 1 );
|
每次都要查詢一個serviceNum 服務號,影響性能(必須要到主內存讀取,並阻止其他cpu修改)。
CLHLock 和MCSLock 則是兩種類型相似的公平鎖,采用鏈表的形式進行排序,
01 |
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
03 |
public class CLHLock {
|
04 |
public static class CLHNode {
|
05 |
private volatile boolean isLocked = true ;
|
08 |
@SuppressWarnings ( "unused" )
|
09 |
private volatile CLHNode tail;
|
10 |
private static final ThreadLocal<CLHNode> LOCAL = new ThreadLocal<CLHNode>();
|
11 |
private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock. class ,
|
12 |
CLHNode. class , "tail" );
|
15 |
CLHNode node = new CLHNode();
|
17 |
CLHNode preNode = UPDATER.getAndSet( this , node);
|
18 |
if (preNode != null ) {
|
19 |
while (preNode.isLocked) {
|
26 |
public void unlock() {
|
27 |
CLHNode node = LOCAL.get();
|
28 |
if (!UPDATER.compareAndSet( this , node, null )) {
|
29 |
node.isLocked = false ;
|
CLHlock是不停的查詢前驅變量, 導致不適合在NUMA 架構下使用(在這種結構下,每個線程分布在不同的物理內存區域)
MCSLock則是對本地變量的節點進行循環。不存在CLHlock 的問題。
01 |
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
03 |
public class MCSLock {
|
04 |
public static class MCSNode {
|
05 |
volatile MCSNode next;
|
06 |
volatile boolean isLocked = true ;
|
09 |
private static final ThreadLocal<MCSNode> NODE = new ThreadLocal<MCSNode>();
|
10 |
@SuppressWarnings ( "unused" )
|
11 |
private volatile MCSNode queue;
|
12 |
private static final AtomicReferenceFieldUpdater<MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock. class ,
|
13 |
MCSNode. class , "queue" );
|
16 |
MCSNode currentNode = new MCSNode();
|
17 |
NODE.set(currentNode);
|
18 |
MCSNode preNode = UPDATER.getAndSet( this , currentNode);
|
19 |
if (preNode != null ) {
|
20 |
preNode.next = currentNode;
|
21 |
while (currentNode.isLocked) {
|
27 |
public void unlock() {
|
28 |
MCSNode currentNode = NODE.get();
|
29 |
if (currentNode.next == null ) {
|
30 |
if (UPDATER.compareAndSet( this , currentNode, null )) {
|
33 |
while (currentNode.next == null ) {
|
37 |
currentNode.next.isLocked = false ;
|
38 |
currentNode.next = null ;
|
從代碼上 看,CLH 要比 MCS 更簡單,
CLH 的隊列是隱式的隊列,沒有真實的後繼結點屬性。
MCS 的隊列是顯式的隊列,有真實的後繼結點屬性。
JUC ReentrantLock 默認內部使用的鎖 即是 CLH鎖(有很多改進的地方,將自旋鎖換成了阻塞鎖等等)。
最後更新:2017-05-23 16:33:02