當前位置:成語大全網 - 新華字典 - 說說java鎖有哪些種類,以及區別

說說java鎖有哪些種類,以及區別

鎖作為並發***享數據,保證壹致性的工具,在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

1、自旋鎖

自旋鎖是采用讓當前線程不停地的在循環體內執行實現的,當循環的條件被其他線程改變時 才能進入臨界區。如下

01 public class SpinLock {

02

03 private AtomicReference<Thread> sign =newAtomicReference<>();

04

05 public void lock(){

06 Thread current = Thread.currentThread();

07 while(!sign .compareAndSet(null, current)){

08 }

09 }

10

11 public void unlock (){

12 Thread current = Thread.currentThread();

13 sign .compareAndSet(current, null);

14 }

15 }

使用了CAS原子操作,lock函數將owner設置為當前線程,並且預測原來的值為空。unlock函數將owner設置為null,並且預測值為當前線程。

當有第二個線程調用lock操作時由於owner值不為空,導致循環壹直被執行,直至第壹個線程調用unlock函數將owner設置為null,第二個線程才能進入臨界區。

由於自旋鎖只是將當前線程不停地執行循環體,不進行線程狀態的改變,所以響應速度更快。但當線程數不停增加時,性能下降明顯,因為每個線程都需要執行,占用CPU時間。如果線程競爭不激烈,並且保持鎖的時間段。適合使用自旋鎖。

註:該例子為非公平鎖,獲得鎖的先後順序,不會按照進入lock的先後順序進行。

Java鎖的種類以及辨析(二):自旋鎖的其他種類

鎖作為並發***享數據,保證壹致性的工具,在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

2.自旋鎖的其他種類

上篇我們講到了自旋鎖,在自旋鎖中 另有三種常見的鎖形式:TicketLock ,CLHlock 和MCSlock

Ticket鎖主要解決的是訪問順序的問題,主要的問題是在多核cpu上

01 package com.alipay.titan.dcc.dal.entity;

02

03 import java.util.concurrent.atomic.AtomicInteger;

04

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

09

10 public void lock() {

11 int myticket = ticketNum.getAndIncrement();

12 LOCAL.set(myticket);

13 while (myticket != serviceNum.get()) {

14 }

15

16 }

17

18 public void unlock() {

19 int myticket = LOCAL.get();

20 serviceNum.compareAndSet(myticket, myticket + 1);

21 }

22 }

每次都要查詢壹個serviceNum 服務號,影響性能(必須要到主內存讀取,並阻止其他cpu修改)。

CLHLock 和MCSLock 則是兩種類型相似的公平鎖,采用鏈表的形式進行排序,

01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;

02

03 public class CLHLock {

04 public static class CLHNode {

05 private volatile boolean isLocked = true;

06 }

07

08 @SuppressWarnings("unused")

09 private volatileCLHNode tail;

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

11 private static finalAtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock.class,

12 CLHNode.class,"tail");

13

14 public void lock() {

15 CLHNode node = new CLHNode();

16 LOCAL.set(node);

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

18 if (preNode != null) {

19 while (preNode.isLocked) {

20 }

21 preNode = null;

22 LOCAL.set(node);

23 }

24 }

25

26 public void unlock() {

27 CLHNode node = LOCAL.get();

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

29 node.isLocked = false;

30 }

31 node = null;

32 }

33 }

CLHlock是不停的查詢前驅變量, 導致不適合在NUMA 架構下使用(在這種結構下,每個線程分布在不同的物理內存區域)

MCSLock則是對本地變量的節點進行循環。不存在CLHlock 的問題。

01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;

02

03 public class MCSLock {

04 public static class MCSNode {

05 volatile MCSNode next;

06 volatile boolean isLocked = true;

07 }

08

09 private static finalThreadLocal<MCSNode> NODE = new ThreadLocal<MCSNode>();

10 @SuppressWarnings("unused")

11 private volatileMCSNode queue;

12 private static finalAtomicReferenceFieldUpdater<MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock.class,

13 MCSNode.class,"queue");

14

15 public void lock() {

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) {

22

23 }

24 }

25 }

26

27 public void unlock() {

28 MCSNode currentNode = NODE.get();

29 if (currentNode.next == null) {

30 if (UPDATER.compareAndSet(this, currentNode, null)) {

31

32 } else {

33 while (currentNode.next == null) {

34 }

35 }

36 } else {

37 currentNode.next.isLocked = false;

38 currentNode.next = null;

39 }

40 }

41 }