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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

高并发编程-自定义带有超时功能的锁

發布時間:2025/3/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高并发编程-自定义带有超时功能的锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 概述
  • 步驟
    • 自定義超時異常處理類
    • ILock接口
    • 實現類
    • 測試
    • 存在的問題
    • 修復存在的問題
    • 超時功能
    • 測試超時功能
  • CustomLock

概述

我們知道synchronized的機制有一個很重要的特點是:使用synchronized, 當一個線程獲取了鎖,其他線程只能一直等待,等待這個獲取鎖的線程釋放鎖,如果這個線程執行時間很長,其他線程就需要一直等待 。 除非獲取鎖的線程執行完了該代碼塊,釋放鎖或者線程執行發生異常,JVM會使線程自動釋放鎖。

當然了J.U.C包中 Doug Lea大神已經設計了非常完美的解決方案,我們這里不討論J.U.C的實現。

我們自己實現一套的話,該如何實現呢? 有幾點需要思考

  • 原有的synchronized功能,必須保證,即一個線程拿到鎖后,其他線程必須等待
  • 誰加的鎖,必須由誰來釋放
  • 加入超時功能
  • 好了,開始吧


    步驟

    自定義超時異常處理類

    既然要設計帶超時功能的鎖, 少不了當超時時,拋出異常,以便上層捕獲處理。

    public class TimeOutException extends RuntimeException {public TimeOutException(String message){super(message);} }

    ILock接口

    約定幾個接口方法: lock 、lock(long timeout)、unlock、getBlockedThread、getBlockedSize 詳見代碼注釋

    package com.artisan.customLock;import java.util.Collection;public interface ILock {/*** 加鎖*/void lock() throws InterruptedException;/*** 加鎖* @param timeout 持有鎖的時間,過了該時間(毫秒) 自動釋放該鎖*/void lock(long timeout) throws InterruptedException,TimeOutException;/*** 釋放鎖*/void unlock();/*** 用于觀察 有哪些線程因沒有獲取到鎖被blocked* @return*/Collection<Thread> getBlockedThreads();/*** 被blocked的線程數量* @return*/int getBlockedSize();}

    實現類

    詳見代碼注釋。 加鎖和釋放鎖方法 使用 synchronized 修飾,否則使用wait && notifyAll拋出異常

    import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Optional;public class CustomLock implements ILock {// 默認false// true: 已經被線程搶到 false: 空閑private boolean lockFlag;// 用于存儲被blocked的線程,方便查看及計算被blocked的線程數量Collection<Thread> blockedThreadCollection = new ArrayList<>();/*** 構造函數中初始化該lockFlag*/public CustomLock(){this.lockFlag = false;}/*** synchronized 修飾該方法* @throws InterruptedException*/@Overridepublic synchronized void lock() throws InterruptedException {// 如果其他線程已經獲取到了鎖,讓該線程waitwhile(lockFlag){// 加入到blockedThreadCollectionblockedThreadCollection.add(Thread.currentThread());// waitthis.wait();}// 如果空閑,將該monitor置為trueblockedThreadCollection.remove(Thread.currentThread());lockFlag = true;}@Overridepublic void lock(long timeout) throws InterruptedException, TimeOutException {}@Overridepublic synchronized void unlock() {// 如果是加鎖的線程// 將Monitor置為空閑this.lockFlag = false;Optional.of(Thread.currentThread().getName() + " 釋放lock").ifPresent(System.out::println);// 喚醒其他正在等待的線程this.notifyAll();}@Overridepublic Collection<Thread> getBlockedThreads() {// blockedThreadCollection 可能被其他線程add 或者remove,這里定義為不可變的集合類型return Collections.unmodifiableCollection(blockedThreadCollection);}@Overridepublic int getBlockedSize() {return blockedThreadCollection.size();} }

    測試

    package com.artisan.customLock;import java.time.LocalTime; import java.util.Optional; import java.util.stream.Stream;public class CustomLockTest {public static void main(String[] args) throws InterruptedException {CustomLock customLock = new CustomLock();// 開啟5個線程Stream.of("T1", "T2", "T3", "T4", "T5").forEach(name -> new Thread(() -> {// 加鎖 處理業務try {// 加鎖customLock.lock();Optional.of(Thread.currentThread().getName() + " hold the Monitor").ifPresent(System.out::println);// 調用業務work();} catch (InterruptedException e) {e.printStackTrace();}finally {// 在finally中釋放鎖customLock.unlock();}}, name).start());}/*** 模擬線程的業務邏輯** @throws InterruptedException*/public static void work() throws InterruptedException {Optional.of(Thread.currentThread().getName() +" begin to work " + LocalTime.now().withNano(0)).ifPresent(System.out::println);Thread.sleep(3_000);}}

    日志輸出:

    "E:\Program Files\Java\jdk1.8.0_161\bin\java" "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=53159:E:\Program Files\JetBrains\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "E:\Program Files\Java\jdk1.8.0_161\jre\lib\charsets.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\deploy.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\access-bridge-64.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\cldrdata.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\dnsns.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jaccess.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jfxrt.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\localedata.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\nashorn.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunec.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunjce_provider.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunmscapi.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunpkcs11.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\zipfs.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\javaws.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jce.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jfr.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jfxswt.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jsse.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\management-agent.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\plugin.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\resources.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\rt.jar;D:\IdeaProjects\mvc\target\classes" com.artisan.customLock.CustomLockTest T1 hold the Monitor T1 begin to work 22:19:14 T1 釋放lock T5 hold the Monitor T5 begin to work 22:19:17 T5 釋放lock T2 hold the Monitor T2 begin to work 22:19:20 T2 釋放lock T4 hold the Monitor T4 begin to work 22:19:23 T4 釋放lock T3 hold the Monitor T3 begin to work 22:19:26 T3 釋放lockProcess finished with exit code 0

    可以看到 確實是一個線程拿到鎖后,其他線程必須等待 。

    針對第二點呢: 誰加的鎖,必須由誰來釋放 .

    我們來測試下

    存在的問題

    針對第二點呢: 誰加的鎖,必須由誰來釋放 .

    我們來測試下 : 假設我們在main線程中調用了unlock方法

    重新運行測試,觀察日志

    T1 hold the Monitor T1 begin to work 22:24:41 main 釋放lock T5 hold the Monitor T5 begin to work 22:24:41 T1 釋放lock T2 hold the Monitor T2 begin to work 22:24:44 T5 釋放lock T4 hold the Monitor T4 begin to work 22:24:44 T2 釋放lock T3 hold the Monitor T3 begin to work 22:24:47 T4 釋放lock T3 釋放lockProcess finished with exit code 0

    T1拿到鎖還沒有工作完,就被主線程釋放了,結果T5又搶到了… 很明顯不對了 。

    修復存在的問題

    見代碼

    再次運行測試 ,OK


    超時功能

    @Overridepublic synchronized void lock(long timeout) throws InterruptedException, TimeOutException {// 入參不合理,直接調用lock ,也可拋出異常if (timeout <= 0 ) lock();// 線程等待的剩余時間long leftTime = timeout;// 計算結束時間long endTime = System.currentTimeMillis() + timeout;while(lockFlag){// 如果超時了,拋出異常if (leftTime <= 0){throw new TimeOutException(Thread.currentThread().getName() + " 超時...");}// 加入到blockedThreadCollectionblockedThreadCollection.add(Thread.currentThread());// wait 指定的時間this.wait(timeout);// 計算是否超時leftTime = endTime - System.currentTimeMillis();}// 如果空閑,將該monitor置為trueblockedThreadCollection.remove(Thread.currentThread());this.lockFlag = true;// 將當前線程置為lockHolderThreadthis.lockHolderThread = Thread.currentThread();}

    測試超時功能

    package com.artisan.customLock;import java.time.LocalTime; import java.util.Optional; import java.util.stream.Stream;public class CustomLockTest {public static void main(String[] args) {CustomLock customLock = new CustomLock();// 開啟5個線程Stream.of("T1", "T2", "T3", "T4", "T5").forEach(name -> new Thread(() -> {// 加鎖 處理業務try {// 加鎖 最多等待100毫秒,如果100ms,沒搶到則中斷執行customLock.lock(100);Optional.of(Thread.currentThread().getName() + " hold the Monitor").ifPresent(System.out::println);// 調用業務work();} catch (InterruptedException e) {e.printStackTrace();} catch (TimeOutException e){Optional.of(Thread.currentThread().getName() + " timeOut").ifPresent(System.out::println);}finally {// 在finally中釋放鎖customLock.unlock();}}, name).start());}/*** 模擬線程的業務邏輯** @throws InterruptedException*/public static void work() throws InterruptedException {Optional.of(Thread.currentThread().getName() +" begin to work " + LocalTime.now().withNano(0)).ifPresent(System.out::println);Thread.sleep(3_000);}}

    運行結果:

    OK。


    CustomLock

    package com.artisan.customLock;import java.time.LocalTime; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Optional;public class CustomLock implements ILock {// 默認false// true: 已經被線程搶到 false: 空閑private boolean lockFlag;// 用于存儲被blocked的線程,方便查看及計算被blocked的線程數量Collection<Thread> blockedThreadCollection = new ArrayList<>();// 當前持有鎖的線程Thread lockHolderThread ;/*** 構造函數中初始化該lockFlag*/public CustomLock(){this.lockFlag = false;}/*** synchronized 修飾該方法* @throws InterruptedException*/@Overridepublic synchronized void lock() throws InterruptedException {// 如果其他線程已經獲取到了鎖,讓該線程waitwhile(lockFlag){// 加入到blockedThreadCollectionblockedThreadCollection.add(Thread.currentThread());// waitthis.wait();}// 如果空閑,將該monitor置為trueblockedThreadCollection.remove(Thread.currentThread());this.lockFlag = true;// 將當前線程置為lockHolderThreadthis.lockHolderThread = Thread.currentThread();}@Overridepublic synchronized void lock(long timeout) throws InterruptedException, TimeOutException {// 入參不合理,直接調用lock ,也可拋出異常if (timeout <= 0 ) lock();// 線程等待的剩余時間long leftTime = timeout;// 計算結束時間long endTime = System.currentTimeMillis() + timeout;while(lockFlag){// 如果超時了,拋出異常if (leftTime <= 0){throw new TimeOutException(Thread.currentThread().getName() + " 超時...");}// 加入到blockedThreadCollectionblockedThreadCollection.add(Thread.currentThread());// wait 指定的時間this.wait(timeout);// 計算是否超時leftTime = endTime - System.currentTimeMillis();}// 如果空閑,將該monitor置為trueblockedThreadCollection.remove(Thread.currentThread());this.lockFlag = true;// 將當前線程置為lockHolderThreadthis.lockHolderThread = Thread.currentThread();}@Overridepublic synchronized void unlock() {// 如果是加鎖的線程if(lockHolderThread == Thread.currentThread()){// 將Monitor置為空閑this.lockFlag = false;Optional.of(Thread.currentThread().getName() + " 釋放lock" + LocalTime.now().withNano(0)).ifPresent(System.out::println);// 喚醒其他正在等待的線程this.notifyAll();}}@Overridepublic Collection<Thread> getBlockedThreads() {// blockedThreadCollection 可能被其他線程add 或者remove,這里定義為不可變的集合類型return Collections.unmodifiableCollection(blockedThreadCollection);}@Overridepublic int getBlockedSize() {return blockedThreadCollection.size();} } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的高并发编程-自定义带有超时功能的锁的全部內容,希望文章能夠幫你解決所遇到的問題。

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