日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java重入锁,再探JAVA重入锁

發(fā)布時間:2023/12/9 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java重入锁,再探JAVA重入锁 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

之前的文章中簡單的為大家介紹了重入鎖JAVA并發(fā)之多線程基礎(chǔ)(2)。這里面也是簡單的為大家介紹了重入鎖的幾種性質(zhì),這里我們就去探索下里面是如何實現(xiàn)的。

我們知道在使用的時候,必須鎖先有定義,然后我們再拿著當前的鎖進行加鎖操作,然后處理業(yè)務,最后是釋放鎖的操作(這里就拿里面非公平鎖的實現(xiàn)來講解)。

字節(jié)碼操作

public class com.montos.lock.ReentrantLockDemo implements java.lang.Runnable {

public static java.util.concurrent.locks.ReentrantLock lock;

public static int k;

public com.montos.lock.ReentrantLockDemo();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

public void run();

Code:

0: iconst_0

1: istore_1

2: iload_1

3: sipush 1000

6: if_icmpge 29 //int類型的值進行棧頂比較

9: getstatic #2 // Field lock:Ljava/util/concurrent/locks/ReentrantLock;

12: invokevirtual #3 // Method java/util/concurrent/locks/ReentrantLock.lock:()V

15: getstatic #4 // Field k:I

18: iconst_1

19: iadd

20: putstatic #4 // Field k:I

23: iinc 1, 1

26: goto 2

29: iconst_0

30: istore_1

31: iload_1

32: sipush 1000

35: if_icmpge 50

38: getstatic #2 // Field lock:Ljava/util/concurrent/locks/ReentrantLock;

41: invokevirtual #5 // Method java/util/concurrent/locks/ReentrantLock.unlock:()V

44: iinc 1, 1

47: goto 31

50: return

public static void main(java.lang.String[]) throws java.lang.InterruptedException;

Code:

0: new #6 // class com/montos/lock/ReentrantLockDemo

3: dup

4: invokespecial #7 // Method "":()V

7: astore_1

8: new #8 // class java/lang/Thread

11: dup

12: aload_1

13: invokespecial #9 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V

16: astore_2

17: new #8 // class java/lang/Thread

20: dup

21: aload_1

22: invokespecial #9 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V

25: astore_3

26: aload_2

27: invokevirtual #10 // Method java/lang/Thread.start:()V

30: aload_3

31: invokevirtual #10 // Method java/lang/Thread.start:()V

34: aload_2

35: invokevirtual #11 // Method java/lang/Thread.join:()V

38: aload_3

39: invokevirtual #11 // Method java/lang/Thread.join:()V

42: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;

45: getstatic #4 // Field k:I

48: invokevirtual #13 // Method java/io/PrintStream.println:(I)V

51: return

static {};

Code:

0: new #14 // class java/util/concurrent/locks/ReentrantLock

3: dup

4: invokespecial #15 // Method java/util/concurrent/locks/ReentrantLock."":()V

7: putstatic #2 // Field lock:Ljava/util/concurrent/locks/ReentrantLock;

10: iconst_0

11: putstatic #4 // Field k:I

14: return

}

復制代碼

這里面無非就是入棧,棧元素比較,出棧放入變量中這些操作,沒有之前的synchronized里面的監(jiān)視器相關(guān)指令限制,只是簡單的一些棧操作。

加鎖操作

final void lock(){

if (compareAndSetState(0, 1)) //將同步狀態(tài)從0變成1 采用cas進行更新

setExclusiveOwnerThread(Thread.currentThread());//設(shè)置當前擁有獨占訪問權(quán)的線程。

else

acquire(1);//沒有獲取到鎖,則進行嘗試操作

}

復制代碼

往下面的選擇走:

public final void acquire(int arg){

//先進行再次嘗試獲取鎖的操作,如果獲取失敗則將當前加入隊列中,并設(shè)置中斷標志。

if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

復制代碼

首先走嘗試獲取鎖的操作(這里還是走非公平鎖的):

final boolean nonfairTryAcquire(int acquires){

final Thread current = Thread.currentThread();//拿到當前線程

int c = getState();//同步狀態(tài)

if (c == 0) {//再次做獲取鎖的操作

if (compareAndSetState(0, acquires)) {

setExclusiveOwnerThread(current);

return true;

}

}

else if (current == getExclusiveOwnerThread()) {//是否是當前線程已經(jīng)占有

int nextc = c + acquires;//原本的狀態(tài)數(shù)值+當前傳入數(shù)值

if (nextc < 0) // overflow

throw new Error("Maximum lock count exceeded");

setState(nextc);//設(shè)置新的狀態(tài)

return true;

}

return false;

}

復制代碼

接著往下走:

private Node addWaiter(Node mode){

//獨占模式進行封裝當前線程

Node node = new Node(Thread.currentThread(), mode);

Node pred = tail;

if (pred != null) {如果尾節(jié)點不為null,將當前的節(jié)點接入并返回

node.prev = pred;

if (compareAndSetTail(pred, node)) {

pred.next = node;

return node;

}

}

enq(node);

return node;

}

復制代碼

繼續(xù)往下走:

private Node enq(final Node node){

for (;;) {//

Node t = tail;

if (t == null) { // 初始化尾節(jié)點

if (compareAndSetHead(new Node()))

tail = head;

} else {

node.prev = t;

if (compareAndSetTail(t, node)) {//尾節(jié)點與當前的節(jié)點互換

t.next = node;

return t;//返回當前節(jié)點

}

}

}

}

復制代碼

接著回去往下走:

final boolean acquireQueued(final Node node, int arg){

boolean failed = true;

try {

boolean interrupted = false;

for (;;) {

final Node p = node.predecessor();

if (p == head && tryAcquire(arg)) {//如果當前節(jié)點前一個節(jié)點是頭節(jié)點,并嘗試獲鎖成功

setHead(node);//設(shè)置當前的頭結(jié)點

p.next = null; // 手動清除引用 幫助GC

failed = false;

return interrupted;

}

//檢測獲取鎖失敗的節(jié)點狀態(tài) 以及暫時掛起并返回當前的中斷標志

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);//取消正在進行的獲取嘗試。

}

}

復制代碼

說真的,咱們直接看失敗的情況,我們接著往下走:

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node){

//檢查和更新無法獲取的節(jié)點的狀態(tài)。

int ws = pred.waitStatus;

if (ws == Node.SIGNAL)

//該節(jié)點已經(jīng)設(shè)置了請求釋放信號狀態(tài),所以可以進行安全掛起

return true;

if (ws > 0) {

do {//清除不需要執(zhí)行的節(jié)點

node.prev = pred = pred.prev;

} while (pred.waitStatus > 0);

pred.next = node;

} else {

//waitstatus必須為0或傳播。表明我們需要信號,但不要掛起。調(diào)用者重試以確保在掛起前無法獲取。

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

}

return false;

}

復制代碼

然后看向下一個方法:

private final boolean parkAndCheckInterrupt(){

LockSupport.park(this);//掛起當前線程

return Thread.interrupted();//返回中斷標識

}

復制代碼

上面的取消獲取隊列里面的節(jié)點就不看了..cancelAcquire(node),里面就是取消正在進行的獲取嘗試。同時將無需的節(jié)點移除。當上面的操作走完之后就設(shè)置當前線程中斷標識。這里面主要流程是說如果加鎖不成功之后,對于當前線程是怎么執(zhí)行操作的,我們可以看到,里面的方法中大部分在獲取不到鎖之后,下一步操作中會再次嘗試獲取下,如果獲取不到才會繼續(xù)執(zhí)行,獲取到了我們就可以直接使用,這里也是多線程操作里面的魅力,每一個空隙中就可能會讓當前線程進行獲得鎖的操作。

釋放鎖操作

釋放鎖的步驟就簡單許多了:

public final boolean release(int arg){

if (tryRelease(arg)) {//嘗試釋放鎖

Node h = head;

if (h != null && h.waitStatus != 0)

unparkSuccessor(h);//喚醒節(jié)點的后續(xù)節(jié)點

return true;

}

return false;

}

復制代碼

咱們繼續(xù)往下看:

protected final boolean tryRelease(int releases){

int c = getState() - releases;//同步狀態(tài)-當前釋放狀態(tài)值

if (Thread.currentThread() != getExclusiveOwnerThread())//如果當前線程不是拿鎖線程,則報監(jiān)視器相關(guān)錯誤

throw new IllegalMonitorStateException();

boolean free = false;

if (c == 0) {

free = true;//只有當前重入次數(shù)為0,才能返回true

setExclusiveOwnerThread(null);//當前獨占線程設(shè)為NULL

}

setState(c);//重新設(shè)置同步狀態(tài)

return free;

}

復制代碼

然后往下走:

private void unparkSuccessor(Node node){

//當前狀態(tài)為負數(shù),則嘗試清除當前的線程狀態(tài)

int ws = node.waitStatus;

if (ws < 0)

compareAndSetWaitStatus(node, ws, 0);

//清除取消或無效的節(jié)點,從尾部向后移動以找到實際節(jié)點

Node s = node.next;

if (s == null || s.waitStatus > 0) {

s = null;

for (Node t = tail; t != null && t != node; t = t.prev)

if (t.waitStatus <= 0)

s = t;

}

if (s != null)

LockSupport.unpark(s.thread);//釋放當前線程

}

復制代碼從上面的順序往下面來看,我們主要發(fā)現(xiàn)線程在拿鎖階段是有許多的操作的,要根據(jù)線程的狀態(tài)再將線程從等待隊列中移除。釋放的時候就顯得簡潔了許多,我們只需要看到當前線程的狀態(tài)-1,然后看看是否是重入的。

我們通過一個簡單的重入鎖代碼可以看到,作者在用無鎖的操作去獲得鎖,這個整體的步驟里面考慮的東西很多,每一個時刻,線程都有可能千變?nèi)f化,我們需要了解的是我們每一個步驟都需要可能發(fā)生的情況。如果能夠考慮到發(fā)生的情況,那么有些步驟就可以直接跳過,我們直接就可以獲得最后的結(jié)果(這塊在線程嘗試獲鎖的階段可以體現(xiàn))。有小伙伴對于重入鎖還有什么看法的可以在下面進行留言,我們可以相互學習,共同進步~

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的java重入锁,再探JAVA重入锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。