Java 多線程使用模式

jopen 8年前發布 | 14K 次閱讀 Java 多線程 安卓開發 Java開發

最常用的兩種線程使用模式:

Future模式與 生產消費者模式

Future模式:

很多時候我們雖然開啟了后臺線程執行某些業務邏輯,但是卻需要后臺線程的執行狀態結果的返回,以便主線程根據這執行結果判斷其他的邏輯執行情況,若這一執行是耗時的往往需要等待的過程。

一種可以優化的情況是:我們并不是立馬需要這個執行狀態,也就是說這個執行狀態的結果獲取是可以后延的,利用Future模式,將這段等待時間利用起來,變串行等待為并行,等待時間內進行其他業務邏輯的操作,最后當所有條件準備好之后,再get這個狀態的執行返回結果;

需要注意的一點是:若get FutureTask結果時,線程內部業務邏輯依舊在執行,也是同樣需要阻塞等待 的。

針對這一情況記錄最近遇到的一個優化實例:保存數據時,利用的一個SynTask操作保存全部數據狀態,UI線程利用ShowDialog阻塞等待狀態,在針對大數據量下Dialog時間過長的問題優化時,分析發現 有部分大時間操作 大概在 1000ms 實在等待數據保存到系統的狀態返回,但是在獲取返回數據之后,并沒有立即使用,而是在獲取之后又執行了大量其他保存操作,最后綜合這部分其他操作和結果進行業務邏輯判定,我得解決方案是將這部分阻塞操作獨立出來,利用FutureTask方式,將系統保存操作拋出(此處注意內存泄漏問題),從而將那些其他操作的運行時間提前,在最后狀態綜合階段再阻塞等待狀態集合做后續業務邏輯操作;最后發現這樣的方式縮短了 超過40%的等待時間,效果很滿意;

生產消費者模式:

這估計是最常見的多線程協同作業模式;其核心是將生產線程與消費線程通過共享內存緩沖區進行邏輯分離解耦,二者各自只關心自己的狀態,生產者搜集工作提交到緩存區,消費者從緩存區獲取處理工作;同時通過緩存區緩解二者性能與執行時間差距;可以一定程度緩解系統并行狀態的性能瓶頸;

順帶提一個 不變模式 ;

不變模式有與生俱來的線程友好,利用final特性,一個變量一旦被創建就無法修改,回避了線程之間的協同作業的同步操作,可以一定程度的提升性能;需要注意的是不變模式由于狀態根本就無法修改,是不進行線程之間狀態修改并同步通信的,所以與同步的應用場景是有差異的;

線程通信:

關于非Double 、非Float類型的原子變量, Java保證在對應線程中返回的值是該線程中存儲的對應變量的值, 但是 并不能保證一個線程寫入的值對于另一個線程也是可見的

較為常用的保證線程間 可靠 通信: 不變量(final字段的靈活運用) 以及同步互斥機制;

同步機制其實包含了兩方面意思:線程之間的互斥與線程間內容共享;同步保證線程有序的修改內容,保證內容的修改在線程之間清晰可見;

同步是削弱并發性能的,所以需要注意過度的鎖同步現象,盡可能減少鎖區工作量,提升性能;還需要注意避免線程間互相等待所造成的死鎖現象;

輕量級同步Volatile:針對原子性操作是可靠的,但是非原子性操作多線程之間也是不可靠的,如 ++ 操作,涉及到讀取,以及運算+1操作,若線程A讀取了變量值之后,在運算操作之前的這段時間內,其他線程完成了對于變量的修改操作,這時候線程A的運算+1操作就是不可靠的;

線程調度:

多線程運行時,哪些線程運行是由線程調度器所決定的,線程在調度器看來也是有優先級的,有一等二等公民之分,但是線程調度器是不可完全依賴的;想要依賴yeild()函數合理讓出Cpu執行時間是不可控的;

過度細膩的線程等級控制是沒有你預期的有用的,可能等級5和等級6并沒有你想的那么大,Java推薦的內置等級有三種MIN,NORME,MAX等級;Java利用setPriority設定線程優先級;

但是Android內置的等級就更多了:Android基于Linux,其線程優先級調整命令是:nice——優先級的范圍為-20 ~ 19 等40個等級,其中數值越小優先級越高,數值越大優先級越低;nice用于設定新建線程優先級,renice用于調整已有線程優先級;renice一般需要權限;

由于Android的40個線程等級,其內置的線程優先級值就遠遠比Java的三級要多了一般有:

THREAD_PRIORITY_DEFAULT,默認的線程優先級,值為0。

THREAD_PRIORITY_LOWEST,最低的線程級別,值為19。

THREAD_PRIORITY_BACKGROUND 后臺線程建議設置這個優先級,值為10。

THREAD_PRIORITY_FOREGROUND 用戶正在交互的UI線程,代碼中無法設置該優先級,系統會按照情況調整到該優先級,值為-2。

THREAD_PRIORITY_DISPLAY 也是與UI交互相關的優先級界別,但是要比THREAD_PRIORITY_FOREGROUND優先,代碼中無法設置,由系統按照情況調整,值為-4。

THREAD_PRIORITY_URGENT_DISPLAY 顯示線程的最高級別,用來處理繪制畫面和檢索輸入事件,代碼中無法設置成該優先級。值為-8。

THREAD_PRIORITY_AUDIO 聲音線程的標準級別,代碼中無法設置為該優先級,值為 -16。

THREAD_PRIORITY_URGENT_AUDIO 聲音線程的最高級別,優先程度較THREAD_PRIORITY_AUDIO要高。代碼中無法設置為該優先級。值為-19。

THREAD_PRIORITY_MORE_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微優先,值為-1。

THREAD_PRIORITY_LESS_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微落后一些,值為1。

以上引用自 技術小黑屋-剖析Android中進程與線程調度之nice

而Android對線程優先級的設定比較簡單:android.os.Process.setThreadPriority方法即可;

需要注意的是:Android中兩種優先級設定的共存,但是nice設定線程優先級與getPriority()并不統一,也就是利用了android.os.Process.setThreadPriority()設定了優先級,并不能利用getPriority()獲取到設定的優先級值,也就是二者其實不是一個系統,想想也是合理的,一個是針對JVM的,一個是針對Linux內核的,完全是兩回事;

順帶提一個遇到的小Tip:

關于Collections.copy();函數的OutOfIndex問題;

Quote:

剖析Android中進程與線程調度之nice

Effective Java

Java程序性能優化

深入理解Java虛擬機

Java并發編程實戰

來自: http://www.itlipan.info/java/2016/01/01/java-thread-mode.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!