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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java并发编程之美-阅读记录6

發(fā)布時間:2024/9/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java并发编程之美-阅读记录6 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java并發(fā)包中鎖

6.1LockSupport工具類

  該類的主要作用就是掛起和喚醒線程,該工具類是創(chuàng)建鎖和其他工具類的基礎。LockSupport類與每個使用他的線程都關聯(lián)一個許可證,在默認情況下調用LockSupport類的方法的線程是不持有許可證的。

  1、void park()

    如果調用park方法的線程已經那都了LockSupport關聯(lián)的許可證的話,那LockSupport.park()會立刻返回,否則就會阻塞掛起。

package com.nxz.blog.otherTest;import java.util.concurrent.locks.LockSupport;public class TestThread004 {/*** LockSupport park* @param args*/public static void main(String[] args) {System.out.println("main-start");// LockSupport的park默認是不持有許可證的,也就是說,調用park方法后,當前線程會阻塞LockSupport.park();System.out.println("main-end");} }

上邊運行結果:如下圖,main線程會阻塞在LockSupport.park()代碼處,不會輸出main-end。

  2、void unpark(Thread thread)方法

    如果參數(shù)thread沒有持有LockSupport許可,調用該方法后,會使thread持有許可證,也就是說會使調用park方法而阻塞的線程返回。(線程intercept中斷之后,park方法也會返回,停止阻塞)

package com.nxz.blog.otherTest;import java.util.concurrent.locks.LockSupport;public class TestThread004 {/*** LockSupport park* @param args*/public static void main(String[] args) {System.out.println("main-start");// 使當前線程(main線程)獲取許可LockSupport.unpark(Thread.currentThread());// 因為上邊已經獲取許可了,所以,下邊這個park方法并不會阻塞線程LockSupport.park();System.out.println("main-end");} }

執(zhí)行結果:

main-start main-end

另外一個例子:

package com.nxz.blog.otherTest;import java.util.concurrent.locks.LockSupport;public class TestThread004 {/*** LockSupport park** @param args*/public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("runnable-start");LockSupport.park();System.out.println("runnable-end");}});t.start();// 目的是使t線程先執(zhí)行,讓t線程調用park方法后阻塞Thread.sleep(1000);System.out.println("main");// 使t線程獲取LockSupport許可,獲取許可后,t線程就可以繼續(xù)向下執(zhí)行了LockSupport.unpark(t);System.out.println("main-end");} }

執(zhí)行結果:

runnable-start main main-end runnable-end

  3、void park(long nanos)

    該方法和park方法類似,只不過是在指定時間后自動返回

  4、void park(Object blocker)

    一般使用的是這個方法而不是無參的park方法,原因是,這個個方法輸出日志時會輸出阻塞的類的信息(而park方法不會輸出)。

6.2抽象同步類AQS

  AbstractQueuedSynchronize抽象同步隊列簡稱AQS,是實現(xiàn)同步器的基礎組件,并發(fā)包中鎖的實現(xiàn),底層都是通過AQS實現(xiàn)的。

  1、基本屬相

// 同步器是一個雙向的FIFO隊列 有頭結點和尾節(jié)點,節(jié)點類型Node為AQS的內部類private transient volatile Node head;private transient volatile Node tail;// 該字段是實現(xiàn)鎖和同步器的關鍵,在不同的實現(xiàn)類中有不同的含義,例如在ReentrantLock中代表當前線程獲取可重入鎖的次數(shù),ReentrantReadWriteLock中,高16位表示讀狀態(tài),也就是獲取讀鎖的次數(shù),低16位掉表寫狀態(tài),也及時寫鎖的次數(shù),Semaphore中代表限號量等等private volatile int state; static final class Node {// 用來標記該線程是獲取共享資源時被阻塞后掛起放入AQS隊列的static final Node SHARED = new Node();// 用來標記該線程是獲取獨占資源師被阻塞后防區(qū)AQS隊列的static final Node EXCLUSIVE = null;// waitstatus狀態(tài)之一, 表示線程被取消了static final int CANCELLED = 1;//waitstatus狀態(tài)之一,表名線程需要喚醒static final int SIGNAL = -1;// 線程在條件隊列里邊等待 static final int CONDITION = -2;// 釋放共享資源師需要通知其他節(jié)點static final int PROPAGATE = -3;// 記錄當前線程的等待狀態(tài),有以上3中狀態(tài)volatile int waitStatus;// 記錄當前節(jié)點的前驅節(jié)點volatile Node prev;// 記錄當前節(jié)點的后繼節(jié)點volatile Node next;// 記錄當前線程volatile Thread thread;// 下一個等待條件變量condition的節(jié)點Node nextWaiter; public class ConditionObject implements Condition, java.io.Serializable {// 該類用來結合所實現(xiàn)線程同步的,每一個ContditionObject是一個條件變量,每一個條件變量對應一個條件對列,每一個條件隊列都是一個單項鏈表,用來存放調用await方法后阻塞的線程// 條件隊列的第一個節(jié)點private transient Node firstWaiter;// 條件隊列的最后一個節(jié)點private transient Node lastWaiter; }

6.3ReentrantLock可重入的獨占鎖

  1、結構圖:

  

  可以看出ReentrantLock最終還是通過AQS實現(xiàn)的,并根據參數(shù)判斷鎖是公平的還是非公平的

// 默認構造是創(chuàng)建一個非公平鎖public ReentrantLock() {sync = new NonfairSync();}// 有參構造,fair:true則創(chuàng)建一個公平鎖,false:創(chuàng)建非公平鎖public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}

  2、void lock()

public void lock() {sync.lock();}// Sync類中為抽象方法,具體實現(xiàn),需要看公平鎖和非公平鎖中的實現(xiàn)方法abstract void lock();// 非公平鎖類static final class NonfairSync extends Sync {// lock實現(xiàn)方法final void lock() {// 通過CAS操作state變量,state默認為0,表名沒有被線程獲取,設置為1成功后,代表該線程獲取鎖成功,此時state為1,并設置exclusiveThread為當前線程if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());else // 調用AQS的acquire方法,AQS內部會條用tryAcquire方法acquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}// 公平鎖static final class FairSync extends Sync {final void lock() {acquire(1);}protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}

  3、lockInterruptibly()方法,可中斷的lock方法

    和lock類似,區(qū)別就是能夠對中斷進行相應(而lock方法對于中斷操作是忽視的)

  4、trylock()方法

    如果當前鎖沒有被其他線程持有,則調用該方法時會立即返回,如果被其他線程持有,則該方法也會立即返回false。(該方法不會阻塞,lock方法會阻塞,即會進入阻塞隊列中)。

public boolean tryLock() {return sync.nonfairTryAcquire(1);}final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 如果state為0,即該鎖沒有被其他線程持有,則該線程通過CAS操作后,持有鎖,會理解返回trueif (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 如果持有鎖的線程是當前線程,則state累計額acquires后,返回trueelse if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}// 返回false,在鎖被其他線程持有時會立即返回falsereturn false;}

  5、釋放鎖unlock()

    如果所被當前線程持有,則state賦為0,即釋放鎖,如果所被當前線程多次持有,則state只是減1,并不會釋放鎖。如果當前線程沒有持有鎖,則跑異常。

6.4ReentrantReadWriteLock讀寫鎖

  采用讀寫分離的策略,允許多個線程可以同時獲取鎖。

  1、結構:有兩個鎖,WriteLock和ReadLock

  

public class ReentrantReadWriteLockimplements ReadWriteLock, java.io.Serializable {// 讀鎖 private final ReentrantReadWriteLock.ReadLock readerLock;// 寫鎖 獨占鎖private final ReentrantReadWriteLock.WriteLock writerLock;// 同步時 繼承自AQS類final Sync sync;public ReentrantReadWriteLock() {this(false);}public ReentrantReadWriteLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();readerLock = new ReadLock(this);writerLock = new WriteLock(this);}public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } }

ReentrantReadWriteLock和ReentrantLock類似,只不過內部分為寫鎖和讀鎖,對于aqs中state變量的控制,在ReentrantLock中,0表示未被線程獲取,而在讀寫鎖中,將state分成兩份,高16位負責記錄讀鎖和低16位負責寫鎖。

?6.5jdk8中新增的StampedLock鎖

  該鎖是jdk8中新增的,提供了3中模式的讀寫控制,當調用獲取鎖的函數(shù)時,會返回一個long類型的變量,也就是戳記(stamp),代表鎖的狀態(tài)。當調用釋放鎖和轉換鎖的時候,需要將該stamp作為參數(shù)傳入。

  寫鎖writeLock:是一個獨占鎖,同一時間只能有一個線程可以獲取鎖(并且是不可沖入鎖)

  悲觀讀鎖readLock:是一個共享鎖,在沒有線程獲取的情況下多個線程可以獲取到鎖,但是只要有線程獲取到寫鎖,則獲取讀鎖的線程都會阻塞(同時該鎖也是不可沖入鎖)

  樂觀讀鎖tryOptimisticRead

  使用案例:

/*** jdk8中stampedLock中提供的例子* 管理二維點的類*/class Point {private double x, y;private final StampedLock sl = new StampedLock();/*** 獨占的方法*/void move(double deltaX, double deltaY) { // an exclusively locked method// 獲取寫鎖long stamp = sl.writeLock();// x y坐標調整try {x += deltaX;y += deltaY;} finally {// 釋放寫鎖sl.unlockWrite(stamp);}}/*** 共享方法,使用了樂觀的共享鎖*/double distanceFromOrigin() { // A read-only method// 獲取樂觀的讀鎖long stamp = sl.tryOptimisticRead();// 獲取point對象坐標的拷貝double currentX = x, currentY = y;// 驗證stamp(也就是之前獲取的鎖是否仍然可用),如果可用的話,則直接進行運算,不可用的話,則獲取一個悲觀的讀鎖readlockif (!sl.validate(stamp)) {// 在stamp不可用情況下,重新獲取一個悲觀讀鎖stamp = sl.readLock();try {// 重新設置xy的拷貝currentX = x;currentY = y;} finally {// 釋放悲觀讀鎖sl.unlockRead(stamp);}}// 返回兩點之間的距離return Math.sqrt(currentX * currentX + currentY * currentY);}// 更原點void moveIfAtOrigin(double newX, double newY) { // upgrade// Could instead start with optimistic, not read modelong stamp = sl.readLock();try {// 如果x=y=0是,修改坐標while (x == 0.0 && y == 0.0) {// 將之前獲取到的讀鎖轉換為一個寫鎖long ws = sl.tryConvertToWriteLock(stamp);//ws不等于0,則代表鎖轉換成功if (ws != 0L) {stamp = ws;x = newX;y = newY;break;} else {// 轉換失敗后,釋放讀鎖,重新獲取一個寫鎖,重復while循環(huán)sl.unlockRead(stamp);stamp = sl.writeLock();}}} finally {// 釋放鎖sl.unlock(stamp);}}}

stampedlock和ReentrantReadWriteLock類似,只不過前者是不可重入鎖,但是前者在提供的樂觀讀鎖在多線程環(huán)境下提供了更好的性能,這是因為樂觀讀鎖不需要進行CAS操作設置鎖的狀態(tài),只是簡單的驗證了一下鎖的stamp是否可用。

?

總結

以上是生活随笔為你收集整理的java并发编程之美-阅读记录6的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。