摘要:這是在具體代碼中發現的不當延遲的問題,極端狀況下可能把內存打爆。
本文分享自華爲雲社區《線程中不當使用延遲問題》,原文做者:技術火炬手 。java
這是在具體代碼中發現的不當延遲的問題,極端狀況下可能把內存打爆。算法
代碼DevLicenseServiceRoaDelegateImpl.javasegmentfault
定義:
api
使用:
數據結構
signalRefreshHelp 定義
併發
這段代碼最大問題是使用延遲算法不當,在極端狀況下會致使內存暴漲,嚴重影響服務程序的性能。高併發
使用sleep實現延遲看起來很是直觀,可是這個在高併發、多請求、長期運行的服務程序裏必須特別當心。這是由於衡量服務程序性能的一個很是重要的指標是QPS, 就是服務程序的處理能力,通常狀況下越大越好;服務程序的總併發能力等於每一個線程的qps;單個線程的QPS = 1000毫秒 / (處理一個請求的毫秒);因此上面那個線程的QPS <= 1000 / 10000 = 0.1 (由於線程sleep了10000毫秒)。性能
這裏的處理邏輯是錯誤的!也有很嚴重的性能隱患,不過幸虧調用這個api 請求很少,纔沒有致使嚴重問題。測試
開發者的意圖是在建立一個任務後,延遲10s執行該任務,處理時序圖以下
spa
假如時間點t1 & t2 捱得很接近的話,線程在執行job1 & job2 也是很接近。
但實際的狀況變成:
就算建立job1 & job2的時間很接近,但job2執行的時間會比預期多了10s;連續提交的任務越多,越容易堆積,這些堆積的任務存放在 blocking queue,一直處處理完畢才刪除;若是這類請求不少的話,很容易引發內存爆掉。
選擇合適的數據結構,默認線程池關聯的隊列是LinkedBlockingQueue , 沒有延遲控制,可使用DelayQueue
DelayQueue內部使用了PriorityQueue 按時間排序;須要本身使用Delayed 接口封裝請求數據
下面是例子
測試代碼,同時加入 3個須要延遲10s的任務
測試結果:
符合預期