Java多線程 - ReentrantLock實際開發中的應用場景

1. 公平鎖,線程排序執行,防餓死應用場景

公平鎖原則必須按照鎖申請時間上先到先得的原則分配機制場景;

1).實現邏輯 上(包括:軟件中函數計算、業務先後流程;硬件中操作實現中順序邏輯)的順序排隊機制的場景;
軟件場景:用戶交互View中對用戶輸入結果分析類,分析過程後面算法依賴上一步結果的場景,例如:推薦算法實現[根據性別、年齡篩選]、阻塞隊列的實現;

硬件場景:需要先分析確認用戶操作類型硬件版本或者廠家,然後發出操作指令;例如:自動售貨機;

2).現實 生活中 時間排序的 公平原則:

例如:客服分配,必須是先到先服務,不能出現餓死現象;公平鎖實現見上文:

公平鎖與非公平鎖的測試demo:邏輯代碼實現那就沒法子實現了;

阻塞隊列的實現就是時間上的公平原則。

2. 非公平鎖,效率的體現者

實際開發中最常用的的場景就是非公平鎖,ReentrantLock無參構造默認就時候非公平鎖;適應場景除了上面公平鎖中提到的其他都是非公平鎖的使用場景;

3. ReentrantLock.Condition線程通信

ReentrantLock.Condition線程通信是最長見的面試題,這裏以最簡單例子:兩個線程之間交替打印 26英文字母和阿拉伯數字爲demo:

private void alternateTask() {
        ReentrantLock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Thread thread1 = new Thread(() -> {
            try {
                lock.lock();
                for (int i = 65; i < 91; i++) {
                    System.out.println("----------thread1------- " + (char) i);
                    condition2.signal();
                    condition1.await();
                }
                condition2.signal();
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                lock.lock();
                for (int i = 0; i < 26; i++) {
                    System.out.println("----------thread2------- " + i);
                    condition1.signal();
                    condition2.await();
                }
                condition1.signal();
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        });
        thread1.start();
        thread2.start();
    }

4.同步功能的使用

實現線程同步鎖synchronized 功能【單例爲例】

  private Singleton() {
    }

    private static Singleton instance;
    private static Lock lock = new ReentrantLock();

    public static Singleton getInstance() {
        lock.lock();
        try {
            if (instance == null) {
                instance = new Singleton();
            }
        } finally {
            lock.unlock();
        }
        return instance;
    }

5. 中斷殺器應用

ReentrantLock中lockInterruptibly()和lock()最大的區別就是中斷相應問題:

lock()是支持中斷相應的阻塞試的獲取方式,因此即使主動中斷了鎖的持有者,但是它不能立即unlock(),仍然要機械版執行完所有操作纔會釋放鎖。

lockInterruptibly()是 優先響應中斷的,這樣有個優勢就是可以通過tryLock()、tryLock(timeout, TimeUnit.SECONDS)方法,中斷優先級低的Task,及時釋放資源給優先級更高的Task,甚至看到網上有人說可以做防止死鎖的優化;
 

 ReentrantLock lock = new ReentrantLock();
        try {
            lock.lockInterruptibly();
            if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
                //TODO
            }else{
                //超時直接中斷優先級低的Task
                Thread.currentThread().interrupt();
                lock.lock();
                //TODO
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           

6. 非重要任務Lock使用

優先級較低的操作讓步給優先級更高的操作,提示代碼效率/用戶體驗;忽略重複觸發

1).用在定時任務時,如果任務執行時間可能超過下次計劃執行時間,確保該有狀態任務只有一個正在執行,忽略重複觸發。

2).用在界面交互時點擊執行較長時間請求操作時,防止多次點擊導致後臺重複執行(忽略重複觸發)。

以上兩種情況多用於進行非重要任務防止重複執行,(如:清除無用臨時文件,檢查某些資源的可用性,數據備份操作等)

tryLock()功能:如果已經獲得鎖立即返回fale,起到防止重複而忽略的效果 

ReentrantLock lock = new ReentrantLock();
      //防止重複執行,執行耗時操作,例如用戶重複點擊
       if (lock.tryLock()) {
           try {
			//TO DO
           } finally {
             lock.unlock();
           }
       }
      

超時放棄

定時操作的例如:錯誤日誌、定時過期緩存清理的操作,遇到優先級更高的操作佔用資源時,暫時放棄本次操作下次再處理,可以起到讓出CPU,提升用戶體驗;

  ReentrantLock lock = new ReentrantLock();
        try {
            if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
                //TO DO
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章