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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程(06):Lock机制下API用法详解

發布時間:2025/3/17 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程(06):Lock机制下API用法详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文源碼:GitHub·點這里 || GitEE·點這里

一、Lock體系結構

1、基礎接口簡介

Lock加鎖相關結構中涉及兩個使用廣泛的基礎API:ReentrantLock類和Condition接口,基本關系如下:

Lock接口

Java并發編程中資源加鎖的根接口之一,規定了資源鎖使用的幾個基礎方法。

ReentrantLock類

實現Lock接口的可重入鎖,即線程如果獲得當前實例的鎖,并進入任務方法,在線程沒有釋放鎖的狀態下,可以再次進入任務方法,特點:互斥排它性,即同一個時刻只有一個線程進入任務。

Condition接口

Condition接口描述可能會與鎖有關聯的條件變量,提供了更強大的功能,例如在線程的等待/通知機制上,Conditon可以實現多路通知和選擇性通知。

2、使用案例

生產消費模式

寫線程向容器中添加數據,讀線程從容器獲取數據,如果容器為空時,讀線程等待。

public class LockAPI01 {private static Lock lock = new ReentrantLock() ;private static Condition condition1 = lock.newCondition() ;private static Condition condition2 = lock.newCondition() ;public static void main(String[] args) throws Exception {List<String> dataList = new ArrayList<>() ;ReadList readList = new ReadList(dataList);WriteList writeList = new WriteList(dataList);new Thread(readList).start();TimeUnit.SECONDS.sleep(2);new Thread(writeList).start();}// 讀數據線程static class ReadList implements Runnable {private List<String> dataList ;public ReadList (List<String> dataList){this.dataList = dataList ;}@Overridepublic void run() {lock.lock();try {if (dataList.size() != 2){System.out.println("Read wait...");condition1.await();}System.out.println("ReadList WakeUp...");for (String element:dataList){System.out.println("ReadList:"+element);}condition2.signalAll();} catch (InterruptedException e){e.fillInStackTrace() ;} finally {lock.unlock();}}}// 寫數據線程static class WriteList implements Runnable {private List<String> dataList ;public WriteList (List<String> dataList){this.dataList = dataList ;}@Overridepublic void run() {lock.lock();try {dataList.add("Java") ;dataList.add("C++") ;condition1.signalAll();System.out.println("Write over...");condition2.await();System.out.println("Write WakeUp...");} catch (InterruptedException e){e.fillInStackTrace() ;} finally {lock.unlock();}}} }

這個生產消費模式和生活中的點餐場景極為類似,用戶下單,通知后廚烹飪,烹飪完成之后通知送餐。

順序執行模式

既然線程執行可以互相通知,那也可以基于該機制實現線程的順序執行,基本思路:在一個線程執行完畢后,基于條件喚醒下個線程。

public class LockAPI02 {public static void main(String[] args) {PrintInfo printInfo = new PrintInfo() ;ExecutorService service = Executors.newFixedThreadPool(3);service.execute(new PrintA(printInfo));service.execute(new PrintB(printInfo));service.execute(new PrintC(printInfo));} } class PrintA implements Runnable {private PrintInfo printInfo ;public PrintA (PrintInfo printInfo){this.printInfo = printInfo ;}@Overridepublic void run() {printInfo.printA ();} } class PrintB implements Runnable {private PrintInfo printInfo ;public PrintB (PrintInfo printInfo){this.printInfo = printInfo ;}@Overridepublic void run() {printInfo.printB ();} } class PrintC implements Runnable {private PrintInfo printInfo ;public PrintC (PrintInfo printInfo){this.printInfo = printInfo ;}@Overridepublic void run() {printInfo.printC ();} } class PrintInfo {// 控制下個執行的線程private String info = "A";private ReentrantLock lock = new ReentrantLock();// 三個線程,三個控制條件Condition conditionA = lock.newCondition();Condition conditionB = lock.newCondition();Condition conditionC = lock.newCondition();public void printA (){try {lock.lock();while (!info.equals("A")) {conditionA.await();}System.out.print("A");info = "B";conditionB.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void printB (){try {lock.lock();while (!info.equals("B")) {conditionB.await();}System.out.print("B");info = "C";conditionC.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void printC (){try {lock.lock();while (!info.equals("C")) {conditionC.await();}System.out.print("C");info = "A";conditionA.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}} }

該案例經常出現在多線程的面試題中,如何實現ABC的順序打印問題,基本思路就是基于線程的等待通知機制,但是實現方式很多,上述只是其中一種方式。

二、讀寫鎖機制

1、基礎API簡介

重入鎖的排它特性決定了性能會產生瓶頸,為了提升性能問題,JDK中還有另一套讀寫鎖機制。讀寫鎖中維護一個共享讀鎖和一個排它寫鎖,在實際開發中,讀的場景還是偏多的,所以讀寫鎖可以很好的提高并發性。

讀寫鎖相關結構中兩個基礎API:ReadWriteLock接口和ReentrantReadWriteLock實現類,基本關系如下:

ReadWriteLock

提供兩個基礎方法,readLock獲取讀機制鎖,writeLock獲取寫機制鎖。

ReentrantReadWriteLock

接口ReadWriteLock的具體實現,特點:基于讀鎖時,其他線程可以進行讀操作,基于寫鎖時,其他線程讀、寫操作都禁止。

2、使用案例

讀寫分離模式

通過讀寫鎖機制,分別向數據容器Map中寫入數據和讀取數據,以此驗證讀寫鎖機制。

public class LockAPI03 {public static void main(String[] args) throws Exception {DataMap dataMap = new DataMap() ;Thread read = new Thread(new GetRun(dataMap)) ;Thread write = new Thread(new PutRun(dataMap)) ;write.start();Thread.sleep(2000);read.start();} } class GetRun implements Runnable {private DataMap dataMap ;public GetRun (DataMap dataMap){this.dataMap = dataMap ;}@Overridepublic void run() {System.out.println("GetRun:"+dataMap.get("myKey"));} } class PutRun implements Runnable {private DataMap dataMap ;public PutRun (DataMap dataMap){this.dataMap = dataMap ;}@Overridepublic void run() {dataMap.put("myKey","myValue");} } class DataMap {Map<String,String> dataMap = new HashMap<>() ;ReadWriteLock rwLock = new ReentrantReadWriteLock() ;Lock readLock = rwLock.readLock() ;Lock writeLock = rwLock.writeLock() ;// 讀取數據public String get (String key){readLock.lock();try{return dataMap.get(key) ;} finally {readLock.unlock();}}// 寫入數據public void put (String key,String value){writeLock.lock();try{dataMap.put(key,value) ;System.out.println("執行寫入結束...");Thread.sleep(10000);} catch (Exception e) {System.out.println("Exception...");} finally {writeLock.unlock();}} }

說明:當put方法一直在睡眠狀態時,因為寫鎖的排它性質,所以讀方法是無法執行的。

三、基礎工具類

LockSupport簡介

LockSupprot定義一組公共靜態方法,這些方法提供最基本的線程阻塞和喚醒功
能。

基礎方法

park():當前線程阻塞,當前線程被中斷或調用unpark方法,park()方法中返回;

park(Object blocker):功能同park(),傳入Object對象,記錄導致線程阻塞的阻塞對象,方便問題排查;

parkNanos(long nanos):指定時間nanos內阻塞當前線程,超時返回;

unpark(Thread thread):喚醒指定處于阻塞狀態的線程;

代碼案例

該流程在購物APP上非常常見,當你準備支付時放棄,會有一個支付失效,在支付失效期內可以隨時回來支付,過期后需要重新選取支付商品。

public class LockAPI04 {public static void main(String[] args) throws Exception {OrderPay orderPay = new OrderPay("UnPaid") ;Thread orderThread = new Thread(orderPay) ;orderThread.start();Thread.sleep(3000);orderPay.changeState("Pay");LockSupport.unpark(orderThread);} } class OrderPay implements Runnable {// 支付狀態private String orderState ;public OrderPay (String orderState){this.orderState = orderState ;}public synchronized void changeState (String orderState){this.orderState = orderState ;}@Overridepublic void run() {if (orderState.equals("UnPaid")){System.out.println("訂單待支付..."+orderState);LockSupport.park(orderState);}System.out.println("orderState="+orderState);System.out.println("訂單準備發貨...");} }

這里基于LockSupport中park和unpark控制線程狀態,實現的等待通知機制。

四、源代碼地址

GitHub·地址 https://github.com/cicadasmile/java-base-parent GitEE·地址 https://gitee.com/cicadasmile/java-base-parent

推薦文章:并發編程系列

序號文章標題
01Java并發:線程的創建方式,狀態周期管理
02Java并發:線程核心機制,基礎概念擴展
03Java并發:多線程并發訪問,同步控制
04Java并發:線程間通信,等待/通知機制
05Java并發:悲觀鎖和樂觀鎖機制

總結

以上是生活随笔為你收集整理的Java并发编程(06):Lock机制下API用法详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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