Android性能優化——線程優化

一、線程調度原理

在任意時刻,CPU只能執行一條指令,每個線程獲取到CPU的使用權之后才可以執行指令也就是說在任意時刻,只有一個線程占用CPU 處于運行狀態
多線程并發,實際上是指多個線程輪流獲取CPU 的使用權然后分別執行各自的任務,在可運行區中,其實有多個線程處于就緒狀態的線程在等待CPU?
而JVM 的一項任務,就是要負責線程的調度線程的調度就是按照特定的機制為多個線程來分配CPU的使用權,

二、線程調度模型

  • 分時調度模型:它的思想是讓線程輪流獲取CPU 的使用權,并且平均每個線程占用CPU 的時間片
  • 搶占式調度模型:Java虛擬機采用的模型,它的思想是優先讓可運行池中優先級高的線程來占用CPU ,如果運行池中的優先級都一樣,那就隨機選擇一個。如果程序想要干預運行順序,那就給每個線程設置一個優先級

三、Android線程調度

由兩個因素來決定:

  • nice值

? ? ?在Process 中定義
? ? ?值越小,優先級越高
? ? ?默認值是:THREAD_PRIORITY_DEFAULT,0
? ? ?最低是19,后臺優先級是16
? ? ?可以設置成負數,優先級更高
? ? ?
如果后臺進程比較多,會影響前臺進程的運行,所以還需要另一種機制來處理這種特殊的情況

  • cgroup?

借助Linux 的cgroup來執行更嚴格的前臺和后臺策略,后臺線程會被隱式的移到后臺group ,當其他組的線程處于工作狀態,那后臺group 的線程就會被限制,使用很小的幾率來利用CPU ,這種分離的調度策略既允許了后臺線程來執行一些任務,同時不會對用戶的前臺線程造成影響,保證前臺線程能使用更多的CPU?
哪些線程會被移到后臺group?

  • 優先級設置的比較低的線程
  • 不在前臺運行的應用程序的線程

注意點

  • 線程過多會導致CPU 頻繁切換,降低線程運行效率異步不能無限制的使用
  • 正確認識到線程執行任務的重要性,來決定哪種優先級,一般優先級與線程的工作量成反比
  • 線程的優先級具有繼承性,比如在UI線程中直接創建一個子線程,它的優先級和UI 線程一樣高

四、異步方式匯總

Thread?

  • ?最簡單,常見的異步方式
  • 不易復用,頻繁創建及銷毀開銷大
  • 復雜場景不易使用,比如要執行一個定時任務thread方式不方便使用

HandlerThread?

  • ?本質是一個Thread ,自帶消息循環
  • ?內部串行執行任務
  • 比較適合那些需要長時間運行,不斷的從隊列中獲取任務的場景

IntentService?

  • 內部實現:繼承自service 在內部創建HandlerThread ,繼承了HandlerThread 的特性
  • 相對于service 來說,它的執行是異步的,不會阻塞UI線程的執行
  • ?優先級較高,不會被系統kill?

AsyncTask?

  • Android提供的異步工具類
  • 內部實現是兩個線程池,一個handler
  • 無需開發者去處理線程切換的問題
  • 需注意版本不一致的問題,實現方式不一致,適配Android版本要在14以上

線程池

  • Java提供的線程池
  • 易復用,減少頻繁創建、銷毀的時間
  • 功能強大:定時,任務隊列,并發控制等

RxJava?

  • 由強大的Scheduler 集合提供
  • 不同的類型區分,IO,Comptution?
  • 如果項目中集成了RxJava 推薦使用RxJava的線程池

五、線程使用準則

  • 嚴禁直接new Thread?
  • 提供基礎線程池供各個業務線使用,避免各個業務線各自維護一套線程池,導致線程數過多
  • 根據任務類型選擇合適的異步方式

? ? 優先級低,長時間執行,使用HandlerThread
? ? 定時執行,使用線程池

  • 創建線程必須命名

? 方便定位線程歸屬
? 運行期,通過Thread.currentThread().setName()修改名字

  • 對關鍵異步任務進行監控

? ? 異步不等于不耗時
? ? AOP的方式來做監控

  • 重視優先級設置,Java的線程調度是一個搶占式的調度模型

? ?Process.setThreadPriority()
? ?可以設置多次

六、鎖定線程創建

  • 項目變大以后收斂線程
  • 項目源碼,三方庫,aar 中都有線程的創建
  • 避免惡化的一種監控預防手段

解決方案
? ?分析:

  • 創建線程的位置去獲取堆棧信息
  • 所有的異步方式,都會走到new Thread?
  • 由于有的源碼拿不到,不能直接在new Thread 的地方直接去獲取堆棧信息,此時特別適合采用Hook手段,在特定的方法之內注入自己的邏輯

? ? 找Hook 點,構造函數或者特定方法
? ? 在這里,就可以找Thread 的構造函數在構造方法里加入自己的邏輯,獲取調用棧信息拿到調用棧信息就能知道哪個調用不是調用我們自己的線程也可以知道調用棧信息是屬于哪一個業務方

DexposedBridge.hookAllConstructors(Thread. class, new XC_MethodHook(
@Overrideprotected void afterHookedMethod (MethodHookParam param) throw Throwable {super.afterHookedMethod (param);Thread thread = (Thread) param.thisObject;LogUtils.i ( msg: thread. getName ()+" stack "+Log.getStackTraceString(new throwable);

七、線程收斂

?常規方案:

  • ?根據線程創建堆棧考量合理性,使用統一線程庫
  • ?各個業務線需要下掉自己的線程庫使用統一的線程庫

基礎庫怎么使用線程

  • ?直接依賴線程庫
  • ?缺點:線程庫更新可能會導致基礎庫更新

優雅的實現

  • 基礎庫內部暴露API setEeecutor 基礎庫只需要修改一次
  • 初始化的時候注入統一的線程庫

統一線程庫

  • 區分任務類型:IO、CPU密集型
  • IO密集型任務不消耗CPU,核心池可以很大
  • CPU密集型任務:核心池大小和CPU核心數相關

八、模擬問題

1.線程使用為什么會遇到問題?

  • 在項目的初期階段,主要是關注業務功能,忽視了基礎庫的建設,具體到線程方面,沒有采用統一的線程池,每個地方使用線程的方式比較亂,同時線程數量比較多
  • 在項目發展壯大之后,遇到了一些線程的性能問題,比如說主線程卡頓,以及一些異步任務執行非常耗時
  • Java的線程調度是一個搶占式的調度模型線程優先級比較重要,但是項目中并沒有做這些區分,對IO和CPU密集型的任務也沒有做區分,很有可能主線程搶不到時間片的情況

2.怎么在項目中對線程進行優化?

  • 首先針對于項目中線程數過多的這種情況,做了線程收斂,通過hook 手段來獲取每個線程運行的堆棧信息
  • 然后結合業務場景來看這個線程是否需要單獨來創建通過這種方式,盡可能在業務層面將線程收斂到統一的線程庫當中,而對于基礎庫,每個基礎庫統一對外暴露一個接口,提供一個線程池實現的能力,在基礎庫使用之前來注入線程庫,這樣基礎庫都用到了線程庫
  • 基礎線程庫針對于IO密集型任務和CPU密集型任務做區分,對于IO密集型任務,比如網絡請求,文件操作,它并不消耗CPU ,所以將核心池設置的比較大,而對于CPU密集型任務,如果核心數數量過高,他可能會導致CPU 頻繁調度,反而會導致執行效率下降,因此根據CPU核心數來決定CPU線程池核心數大小
  • ?還做了其他處理,比如對重要的異步邏輯進行監控,監控他的執行時間,同時在執行異步任務的時候注重優先級以及線程名的設置

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41477.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41477.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41477.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

系統安全測試要怎么做?

進行系統安全測試時,可以按照以下詳細的步驟進行: 1、信息收集和分析: 收集系統的相關信息,包括架構、部署環境、使用的框架和技術等。 分析系統的安全需求、威脅模型和安全策略等文檔。 2、威脅建模和風險評估: 使…

調用被fishhook的原函數

OC類如果通過runtime被hook了,可以通過逆序遍歷方法列表的方式調用原方法。 那系統庫的C函數被fish hook了該怎么辦呢? 原理和OC類異曲同工,即通過系統函數dlopen()獲取動態庫,以動態庫為參數通過系統函數dlsym()即可獲取目標系統…

leetcode292. Nim 游戲(博弈論 - java)

Nim 游戲 Nim 游戲題目描述博弈論 上期經典算法 Nim 游戲 難度 - 簡單 原題鏈接 - Nim游戲 題目描述 你和你的朋友,兩個人一起玩 Nim 游戲: 桌子上有一堆石頭。 你們輪流進行自己的回合, 你作為先手 。 每一回合,輪到的人拿掉 1 -…

494. 目標和

494. 目標和 原題鏈接:完成情況:解題思路:數組回溯法動態規劃 參考代碼:數組回溯法__494目標和__動態規劃 經驗吸取 原題鏈接: 494. 目標和 https://leetcode.cn/problems/target-sum/description/ 完成情況&#…

Android進階之多級列表

遇到一個需求需要顯示多級列表,因為界面是在平板上的,所以層級是從左向右往下排的,類似于 我當時的寫法是在xml布局里一個個RecyclerView往下排的 當然前提是已經規定好最大的層級我才敢如此去寫界面,如果已經明確規定只有兩級或…

69 # 強制緩存的配置

強制緩存 強制緩存:以后的請求都不需要訪問服務器,狀態碼為 200協商緩存:每次都判斷一下,告訴是否需要找緩存,狀態碼為 304 默認強制緩存,不緩存首頁(如果已經斷網,那這個頁面應該…

Python發送QQ郵件

使用Python的smtplib可以發送QQ郵件,代碼如下 #!/usr/bin/python3 import smtplib from email.mime.text import MIMEText from email.header import Headersender 111qq.com # 發送郵箱 receivers [222qq.com] # 接收郵箱 auth_code "abc" # 授權…

Dockerfile概念、鏡像原理、制作及案例講解

1.Docker鏡像原理 Linux文件操作系統講解 2.鏡像如何制作 3.Dockerfile概念 Docker網址:https://hub.docker.com 3.1 Dockerfile關鍵字 4.案例

【數據結構OJ題】鏈表分割

原題鏈接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId8&&tqId11004&rp2&ru/activity/oj&qru/ta/cracking-the-coding-interview/question-ranking 目錄 1. 題目描述 2. 思路分析 3. 代碼實現 1. 題目描述 2…

AMD卡啟動Stable Diffusion AI繪畫的方法

WindowsAMD安裝法 1.安裝python 3.10.6,在python官網上下載安裝程序,***重要*** 在安裝的第一個窗口下方勾選“將python添加到path”。 2.安裝git 3.WindowsAMD使用AUTOMATIC1111的directml這一個fork,在這個頁面的第一段:https:/…

題目:2614.對角線上的質數

??題目來源: leetcode題目,網址:2614. 對角線上的質數 - 力扣(LeetCode) 解題思路: 遍歷對角線上的元素,返回最大的質數或 0 即可。 解題代碼: class Solution {public int dia…

e.target.value和 binding.value 區別

e.target.value 和 binding.value 都是在 Vue.js 中用于處理事件綁定時的值,但它們的使用場景和含義有所不同,分別用于普通的 DOM 事件和自定義指令。 e.target.value: 這是常用于原生 DOM 事件處理函數中的一個屬性,用于獲取事件…

爬蟲逆向實戰(十七)--某某丁簡歷登錄

一、數據接口分析 主頁地址:某某丁簡歷 1、抓包 通過抓包可以發現數據接口是submit 2、判斷是否有加密參數 請求參數是否加密? 通過查看“載荷”模塊可以發現有一個enPassword加密參數 請求頭是否加密? 通過查看請求頭可以發現有一個To…

【面試高頻題】難度 3/5,字典樹熱門運用題

題目描述 這是 LeetCode 上的 「745. 前綴和后綴搜索」 ,難度為 「困難」。 Tag : 「字典樹」 設計一個包含一些單詞的特殊詞典,并能夠通過前綴和后綴來檢索單詞。 實現 WordFilter 類: WordFilter(string[] words) 使用詞典中的單詞 words 初…

單片機之從C語言基礎到專家編程 - 4 C語言基礎 - 4.9 變量與常量

基本數據類型可以作為變量與常量使用,顧名思義,變量運行時可以改變其值,常量運行時不會改變其值。 常量分為整型常量、浮點型常量、字符常量、字符串常量和符號常量。 通常用#define來定義一個標識符來表示一個常量 用type name 常量來定義一個變量,…

無法將“環境變量”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱(pycharm)

無法將“配置的任何一個環境變量”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱。 記錄解決“無法將“C:......conda.exe”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱”以及“表達式或語句中包含意外的標記”的系列問題(VSCode開發環境)一、Conda.exe無法正常識…

ROS2 學習(三)話題

話題 節點之間的通信。 叫話題很形象。發布者發布一定數據類型的話題,訂閱者訂閱發布者。 訂閱者發布者不唯一。 異步通信,適用于周期發布的數據而不是邏輯性強的數據。 .msg 格式的消息結構,一種通信接口。 每個話題 topic 有話題名&a…

【Java高級開發高頻面試題】面試者角度的口述版

文章目錄 1.具備扎實的Java基礎集合HashMap底層工作原理HashMap版本問題HashMap并發修改異常HashMap影響HashMap性能的因素HashMap使用優化 SynchronizedThreadLocalAQS線程池JVM內存模型類加載機制與雙親委派垃圾回收算法、垃圾回收器、空間分配擔保策略引用計數器算法、可達性…

創建 Web 內容目錄

創建 Web 內容目錄 按照下方所述,創建一個名為 /home/curtis/ansible/webcontent.yml 的 playbook : 該 playbook 在 dev 主機組中的受管節點上運行 創建符合下列要求的目錄 /webdev : 所有者為 webdev 組 具有常規權限:ownerread…

Nginx反向代理

目錄 一.簡介1.反向代理 二.案例1.案例12.案例2 一.簡介 1.反向代理 1.1反向代理: 是指代理服務器來接收Internet上的客戶端請求,然后將請求轉發給內部網絡上的服務器,并將從服務器上得到的結果返回給客戶端。此時代理服務器對外就表現為一…