android 線程池

為什么用線程池

創建/銷毀線程伴隨著系統開銷,過于頻繁的創建/銷毀線程,會很大程度上影響處理效率

例如:

  • 記創建線程消耗時間T1,執行任務消耗時間T2,銷毀線程消耗時間T3

如果T1+T3>T2,那么是不是說開啟一個線程來執行這個任務太不劃算了!

正好,線程池緩存線程,可用已有的閑置線程來執行新任務,避免了T1+T3帶來的系統開銷

  • 線程并發數量過多,搶占系統資源從而導致阻塞
    我們知道線程能共享系統資源,如果同時執行的線程過多,就有可能導致系統資源不足而產生阻塞的情況,運用線程池能有效的控制線程最大并發數,避免以上的問題

  • 對線程進行一些簡單的管理
    比如:延時執行、定時循環執行的策略等
    運用線程池都能進行很好的實現

線程池ThreadPoolExecutor

既然Android中線程池來自于Java,那么研究Android線程池其實也可以說是研究Java中的線程池

在Java中,線程池的概念是Executor這個接口,具體實現為ThreadPoolExecutor類,學習Java中的線程池,就可以直接學習他了

對線程池的配置,就是對ThreadPoolExecutor構造函數的參數的配置,既然這些參數這么重要,就來看看構造函數的各個參數吧

ThreadPoolExecutor提供了四個構造函數

//五個參數的構造函數
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue)

//六個參數的構造函數-1
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory)

//六個參數的構造函數-2
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler)

//七個參數的構造函數
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

我知道你看到這些構造函數和我一樣也是嚇呆了,但其實一共就7種類型,理解起來簡直和理解一周有7天一樣簡單,而且一周有兩天是周末,其實也就只有5天需要了解!相信我,畢竟扯皮,我比較擅長

int corePoolSize => 該線程池中核心線程數最大值

核心線程:

線程池新建線程的時候,如果當前線程總數小于corePoolSize,則新建的是核心線程,如果超過corePoolSize,則新建的是非核心線程

核心線程默認情況下會一直存活在線程池中,即使這個核心線程啥也不干(閑置狀態)。

如果指定ThreadPoolExecutor的allowCoreThreadTimeOut這個屬性為true,那么核心線程如果不干活(閑置狀態)的話,超過一定時間(時長下面參數決定),就會被銷毀掉

很好理解吧,正常情況下你不干活我也養你,因為我總有用到你的時候,但有時候特殊情況(比如我自己都養不起了),那你不干活我就要把你干掉了
int maximumPoolSize

該線程池中線程總數最大值

線程總數 = 核心線程數 + 非核心線程數。核心線程在上面解釋過了,這里說下非核心線程:

不是核心線程的線程,在上面解釋過了
long keepAliveTime

該線程池中非核心線程閑置超時時長

一個非核心線程,如果不干活(閑置狀態)的時長超過這個參數所設定的時長,就會被銷毀掉

如果設置allowCoreThreadTimeOut = true,則會作用于核心線程
TimeUnit unit

keepAliveTime的單位,TimeUnit是一個枚舉類型,其包括:

NANOSECONDS : 1微毫秒 = 1微秒 / 1000
MICROSECONDS : 1微秒 = 1毫秒 / 1000
MILLISECONDS : 1毫秒 = 1秒 /1000
SECONDS : 秒
MINUTES : 分
HOURS : 小時
DAYS : 天
BlockingQueue workQueue

該線程池中的任務隊列:維護著等待執行的Runnable對象

當所有的核心線程都在干活時,新添加的任務會被添加到這個隊列中等待處理,如果隊列滿了,則新建非核心線程執行任務

常用的workQueue類型:

SynchronousQueue:這個隊列接收到任務的時候,會直接提交給線程處理,而不保留它,如果所有線程都在工作怎么辦?那就新建一個線程來處理這個任務!所以為了保證不出現<線程數達到了maximumPoolSize而不能新建線程>的錯誤,使用這個類型隊列的時候,maximumPoolSize一般指定成Integer.MAX_VALUE,即無限大

LinkedBlockingQueue:這個隊列接收到任務的時候,如果當前線程數小于核心線程數,則新建線程(核心線程)處理任務;如果當前線程數等于核心線程數,則進入隊列等待。由于這個隊列沒有最大值限制,即所有超過核心線程數的任務都將被添加到隊列中,這也就導致了maximumPoolSize的設定失效,因為總線程數永遠不會超過corePoolSize

ArrayBlockingQueue:可以限定隊列的長度,接收到任務的時候,如果沒有達到corePoolSize的值,則新建線程(核心線程)執行任務,如果達到了,則入隊等候,如果隊列已滿,則新建線程(非核心線程)執行任務,又如果總線程數到了maximumPoolSize,并且隊列也滿了,則發生錯誤

DelayQueue:隊列內元素必須實現Delayed接口,這就意味著你傳進去的任務必須先實現Delayed接口。這個隊列接收到任務時,首先先入隊,只有達到了指定的延時時間,才會執行任務
ThreadFactory threadFactory創建線程的方式,這是一個接口,你new他的時候需要實現他的Thread newThread(Runnable r)方法

小伙伴應該知道AsyncTask是對線程池的封裝吧?那就直接放一個AsyncTask新建線程池的threadFactory參數源碼吧:

new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);

public Thread new Thread(Runnable r) {return new Thread(r,"AsyncTask #" + mCount.getAndIncrement());
}

}
這么簡單?就給線程起了個名?
RejectedExecutionHandler handler

這玩意兒就是拋出異常專用的,比如上面提到的兩個錯誤發生了,就會由這個handler拋出異常,你不指定他也有個默認的

新建一個線程池的時候,一般只用5個參數的構造函數。

向ThreadPoolExecutor添加任務

那說了這么多,你可能有疑惑,我知道new一個ThreadPoolExecutor,大概知道各個參數是干嘛的,可是我new完了,怎么向線程池提交一個要執行的任務啊?

通過ThreadPoolExecutor.execute(Runnable command)方法即可向線程池內添加一個任務

ThreadPoolExecutor的策略

上面介紹參數的時候其實已經說到了ThreadPoolExecutor執行的策略,這里給總結一下,當一個任務被添加進線程池時:

線程數量未達到corePoolSize,則新建一個線程(核心線程)執行任務
線程數量達到了corePools,則將任務移入隊列等待
隊列已滿,新建線程(非核心線程)執行任務
隊列已滿,總線程數又達到了maximumPoolSize,就會由上面RejectedExecutionHandler拋出異常
常見四種線程池

如果你不想自己寫一個線程池,那么你可以從下面看看有沒有符合你要求的(一般都夠用了),如果有,那么很好你直接用就行了,如果沒有,那你就老老實實自己去寫一個吧

Java通過Executors提供了四種線程池,這四種線程池都是直接或間接配置ThreadPoolExecutor的參數實現的,下面我都會貼出這四種線程池構造函數的源碼,各位大佬們一看便知!

來,走起:

CachedThreadPool()

可緩存線程池:

線程數無限制
有空閑線程則復用空閑線程,若無空閑線程則新建線程
一定程序減少頻繁創建/銷毀線程,減少系統開銷
創建方法:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

源碼:

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
通過我上面行云流水談笑風生天馬行空滔滔不絕的對各種參數的說明,這個源碼你肯定一眼就看懂了,想都不用想(下面三種一樣啦)

FixedThreadPool()

定長線程池:

可控制線程最大并發數(同時執行的線程數)
超出的線程會在隊列中等待
創建方法:

//nThreads => 最大線程數即maximumPoolSize
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

//threadFactory => 創建線程的方法
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
源碼:

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
ScheduledThreadPool()

定長線程池:

支持定時及周期性任務執行。
創建方法:

//nThreads => 最大線程數即maximumPoolSize
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
源碼:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}

//ScheduledThreadPoolExecutor():
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
SingleThreadExecutor()

單線程化的線程池:

有且僅有一個工作線程執行任務
所有任務按照指定順序執行,即遵循隊列的入隊出隊規則
創建方法:

ExecutorService singleThreadPool = Executors.newSingleThreadPool();

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

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

相關文章

datatable轉化泛型

public class ConvertHelper<T>where T:new() { /// <summary> /// 利用反射和泛型 /// </summary> /// <param name"dt"></param> /// <returns></returns> public static List<T> ConvertToList(DataTable dt) { …

【躍遷之路】【651天】程序員高效學習方法論探索系列(實驗階段408-2018.11.24)...

(收集箱&#xff08;每日一記&#xff0c;每周六整理&#xff09;)專欄 實驗說明 從2017.10.6起&#xff0c;開啟這個系列&#xff0c;目標只有一個&#xff1a;探索新的學習方法&#xff0c;實現躍遷式成長實驗期2年&#xff08;2017.10.06 - 2019.10.06&#xff09;我將以自己…

更換mysql_Docker搭建MySQL主從復制

Docker搭建MySQL主從復制 主從服務器上分別安裝Docker 1.1 Docker 要求 CentOS 系統的內核版本高于 3.10 [rootlocalhost ~]# uname -r 3.10.0-693.el7.x86_641.2 確保 yum 包更新到最新。 [rootlocalhost ~]# sudo yum update Loaded plugins: fastestmirror, langpacks Loadi…

dll文件的c++制作dll文件的c++制作

dll文件的c制作1、首先用vs2005建立一個c的dll動態鏈接庫文件&#xff0c;這時&#xff0c;// DllTest.cpp : 定義 DLL 應用程序的入口點。//#include "stdafx.h"//#include "DllTest.h"#ifdef _MANAGED#pragma managed(push, off)#endifBOOL APIENTRY Dll…

理解ConstraintLayout 對性能的好處

自從在17年GoogleI/O大會宣布了Constraintlayout,我們持續提升了布局的穩定性和布局編輯的支持。我們還為ConstraintLayout添加了一些新特性支持創建不同類型的布局&#xff0c;添加這些新特性&#xff0c;可以明顯的提升性能&#xff0c;在這里&#xff0c;我門將討論Contrain…

數據湖 data lake_在Data Lake中高效更新TB級數據的模式

數據湖 data lakeGOAL: This post discusses SQL “UPDATE” statement equivalent for a data lake (object) storage using Apache Spark execution engine. To further clarify consider this, when you need to perform conditional updates to a massive table in a relat…

如何理解運維

運維工程師&#xff08;運營&#xff09;&#xff0c;負責維護并確保整個服務的高可用性&#xff0c;同時不斷優化系統架構提升部署效率&#xff0c;優化資源利用率提高整體的投資回報率。運維工程師面對的最大挑戰是大規模集群的管理問題&#xff0c;如何管理好幾十萬臺服務器…

advanced installer更換程序id_好程序員web前端培訓分享kbone高級-事件系統

好程序員web前端培訓分享kbone高級-事件系統&#xff1a;1、用法&#xff0c;對于多頁面的應用&#xff0c;在 Web 端可以直接通過 a 標簽或者 location 對象進行跳轉&#xff0c;但是在小程序中則行不通&#xff1b;同時 Web 端的頁面 url 實現和小程序頁面路由也是完全不一樣…

ai對話機器人實現方案_顯然地引入了AI —無代碼機器學習解決方案

ai對話機器人實現方案A couple of folks from Obviously.ai contacted me a few days back to introduce their service — a completely no-code machine learning automation tool. I was a bit skeptical at first, as I always am with supposedly fully-automated solutio…

網絡負載平衡的

網絡負載平衡允許你將傳入的請求傳播到最多達32臺的服務器上&#xff0c;即可以使用最多32臺服務器共同分擔對外的網絡請求服務。網絡負載平衡技術保證即使是在負載很重的情況下它們也能作出快速響應。 網絡負載平衡對外只須提供一個IP地址&#xff08;或域名&#xff09;。 如…

透明狀態欄導致windowSoftInputMode:adjustResize失效問題

當我們通過下面代碼&#xff1a; getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 設置狀態欄透明&#xff0c;當界面存在EditText時&#xff0c;在activity里面設置windowSoftInputMode:…

[TimLinux] JavaScript 元素動態顯示

1. css的opacity屬性 這個屬性用于&#xff1a;設置元素的不透明級別&#xff0c;取值范圍&#xff1a;從 0.0 &#xff08;完全透明&#xff09;到 1.0&#xff08;完全不透明&#xff09;&#xff0c;元素所在的文本流還在。這個屬性的動態變化可以用來設置元素的淡入淡出效果…

神經網絡 CNN

# encodingutf-8import tensorflow as tfimport numpy as npfrom tensorflow.examples.tutorials.mnist import input_datamnist input_data.read_data_sets(MNIST_data, one_hotTrue)def weight_variable(shape): initial tf.truncated_normal(shape, stddev0.1) # 定義…

圖片中的暖色或冷色濾色片是否會帶來更多點擊? —機器學習A / B測試

A/B test on ads is the art of choosing the best advertisement that optimizes your goal (number of clicks, likes, etc). For example, if you change a simple thing like a filter in your pictures you will drive more traffic to your links.廣告的A / B測試是一種選…

3d制作中需要注意的問題_淺談線路板制作時需要注意的問題

PCB電路板是電子設備重要的基礎組裝部件&#xff0c;在制作PCB電路板時&#xff0c;只有將各個方面都考慮清楚&#xff0c;才能保證電子設備在使用時不會出現問題。今天小編就與大家一起分享線路板制作時需要注意的問題&#xff0c;歸納一下幾點&#xff1a;1、考慮制作類型電路…

冷啟動、熱啟動時間性能優化

用戶希望應用程序能夠快速響應并加載。 一個啟動速度慢的應用程序不符合這個期望&#xff0c;可能會令用戶失望。 這種糟糕的體驗可能會導致用戶在應用商店中對您的應用進行糟糕的評價&#xff0c;甚至完全放棄您的應用。 本文檔提供的信息可幫助您優化應用的啟動時間。 它首先…

python:lambda、filter、map、reduce

lambda 為關鍵字。filter&#xff0c;map&#xff0c;reduce為內置函數。 lambda&#xff1a;實現python中單行最小函數。 g lambda x: x * 2 #相當于 def g(x):return x*2print(g(3))# 6 注意&#xff1a;這里直接g(3)可以執行&#xff0c;但沒有輸出的&#xff0c;前面的…

集群

原文地址&#xff1a;http://www.microsoft.com/china/MSDN/library/windev/COMponentdev/CdappCEnter.mspx?mfrtrue 本文假設讀者熟悉 Windows 2000、COM、IIS 5.0 摘要 Application Center 2000 簡化了從基于 Microsoft .NET 的應用程序到群集的部署&#xff0c;群集是一組…

Myeclipes連接Mysql數據庫配置

相信大家在網站上也找到了許多關于myeclipes如何連接mysql數據庫的解決方案&#xff0c;雖然每一步都按照他的步驟來&#xff0c;可到最后還是提示連接失敗&#xff0c;有的方案可能應個人設備而異&#xff0c;配置環境不同導致。經過個人多方探索終于找到一個簡單便捷的配置方…

cnn圖像二分類 python_人工智能Keras圖像分類器(CNN卷積神經網絡的圖片識別篇)...

上期文章我們分享了人工智能Keras圖像分類器(CNN卷積神經網絡的圖片識別的訓練模型)&#xff0c;本期我們使用預訓練模型對圖片進行識別&#xff1a;Keras CNN卷積神經網絡模型訓練導入第三方庫from keras.preprocessing.image import img_to_arrayfrom keras.models import lo…