面試總結(6):ScheduledExecutorService的使用
前言
android的執行緒池主要有四個:
newSingleThreadExecutor:單執行緒池,同時只有一個執行緒在跑。
newCachedThreadPool() :回收型執行緒池,可以重複利用之前建立過的執行緒,執行執行緒最大數是Integer.MAX_VALUE。
newFixedThreadPool() :固定大小的執行緒池,跟回收型執行緒池類似,只是可以限制同時執行的執行緒數量
哎???第四個是什麼來著,不知道你有沒有想起來,反正我是沒記住,結果面試的時候就栽了個跟頭。
正文
第四種執行緒池是ScheduledExecutorService,我平時沒有用過,他的最大優點除了執行緒池的特性以外,可以實現迴圈或延遲任務。
ScheduledExecutorService 和 Timer 的區別
Timer的內部只有一個執行緒,如果有多個任務的話就會順序執行,這樣我們的延遲時間和迴圈時間就會出現問題。
ScheduledExecutorService是執行緒池,所以就不會出現這個情況,在對延遲任務和迴圈任務要求嚴格的時候,就需要考慮使用ScheduledExecutorService了。
ScheduledExecutorService的用法主要有三個:
public class MainActivity extends AppCompatActivity {
// 通過靜態方法建立ScheduledExecutorService的例項
private ScheduledExecutorService mScheduledExecutorService = Executors.newScheduledThreadPool(4);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 延時任務
mScheduledExecutorService.schedule(threadFactory.newThread(new Runnable() {
@Override
public void run() {
Log.e("lzp", "first task");
}
}), 1, TimeUnit.SECONDS);
// 迴圈任務,按照上一次任務的發起時間計算下一次任務的開始時間
mScheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.e("lzp", "first:" + System.currentTimeMillis() / 1000);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 1, 1, TimeUnit.SECONDS);
// 迴圈任務,以上一次任務的結束時間計算下一次任務的開始時間
mScheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
Log.e("lzp", "scheduleWithFixedDelay:" + System.currentTimeMillis() / 1000);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 1, 1, TimeUnit.SECONDS);
}
}
在程式碼中已經有註釋說明這三個方法的用法,重點是scheduleAtFixedRate和scheduleWithFixedDelay的區別,下面看具體看一下Log資訊:
首先是scheduleAtFixedRate:
從log上看,我們的迴圈任務嚴格按照每一秒發起一次,sleep(3000)對於任務的開啟是沒有影響的,也就是以上一個任務的開始時間 + 延遲時間 = 下一個任務的開始時間。
然後是scheduleWithFixedDelay:
從log上看,每一個任務的時間間隔是4秒,而不是我們設定的間隔1秒,任務要耗時3秒,兩個時間相加正好是4秒,那麼之前程式碼註釋的解釋就說的通了:以上一次任務的結束時間 + 延遲時間 = 下一次任務的開始時間。
擴充套件:ThreadFactory
因為線上程池的構造方法中,有ThreadFactory引數,所以就來簡單介紹一個ThreadFactory:
執行緒工廠,可以對傳入的Runnable進行加工操作,典型的工廠模式,需要實現newThread(@NonNull Runnable r) 方法返回加工後的執行緒。
看一下具體的程式碼:
private ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(@NonNull final Runnable r) {
return new Thread() {
@Override
public void run() {
r.run();
Log.e("lzp", "嘿嘿嘿");
}
};
}
};
例如上面的程式碼,我在引數Runnable物件的run方法後,增加了一句log列印。
然後修改MainActivity的呼叫:
mScheduledExecutorService.schedule(threadFactory.newThread(new Runnable() {
@Override
public void run() {
Log.e("lzp", "first task");
}
}), 1, TimeUnit.SECONDS);
這裡面我傳入ThreadFactory加工過後的Runnable,我們推斷,最後應該會列印兩句:first task 和 嘿嘿嘿,執行一下看看是不是符合我們的期望:
果然結果沒有讓我們失望。
然後我有了一個想法,我要給執行緒池所有的執行緒都加工一下:
private ScheduledExecutorService mScheduledExecutorService = Executors.newScheduledThreadPool(4, new ThreadFactory() {
@Override
public Thread newThread(@NonNull Runnable r) {
return new Thread(r){
@Override
public void run() {
Log.e("lzp", "newThread");
super.run();
Log.e("lzp", "newThread over");
}
};
}
});
我在Runnable引數的run方法前後增加了列印,於是我迫不及待的運行了app:
經過短暫的喜悅,我發現我的希望落空了,出現了兩個問題:
1、Log.e(“lzp”, “newThread over”) 這一句為什麼沒有執行???
2、為什麼ThreadFactory.newThread() 只執行了四次。
帶著疑問我開始檢視原始碼,經過仔細的思考,找到了問題的原因,這裡就簡單解釋一下:
1、執行緒池只會建立最大併發數(corePoolSize)的Worker物件。
2、Worker物件內部包含了Thread和Runnable資訊。
3、新增任務時:
如果Worker沒有到最大值,就建立Worker(通過ThreadFactory的newThread新建了Thread,所以Thread的數量等於Worker數量);
如果已經是最大,就把任務放到佇列(Quene)中。3、任務執行中:
如果Worker的Runnable不為空,執行Runnable,執行結束,Runnable設定為空;
如果Worker的Runnable為空,從佇列中取出任務執行。4、Runnable執行結束,執行緒池內部直接退出了執行緒。
弄懂了內部的機制,剛才的問題就全都弄明白了,還發現android的設計者是不希望我們通過這種方法去影響Runnable的實現方法,但是可以去改變執行緒Thread物件的屬性,例如優先順序等等。
總結
這一篇我們先去弄懂了ScheduledExecutorService的特性和用法,然後瞭解了ThreadFactory的用法,最後兩者結合使用,分析並解決可能出現的問題。
由於執行緒池的原始碼還是很多的,這裡就不具體的解釋了,想具體瞭解的朋友可以自己去檢視原始碼或者網上檢視資料。
最後帶上原始碼連結,有問題或者建議可以留言。
相關推薦
面試總結(6):ScheduledExecutorService的使用
前言 android的執行緒池主要有四個: newSingleThreadExecutor:單執行緒池,同時只有一個執行緒在跑。 newCachedThreadPool() :回收型執行緒池,可以重複利用之前建立過的執行緒,執行執行緒最大數是In
git操作總結(6):刪除檔案以及刪除檔案後恢復檔案
1.確實要從版本庫中刪除該檔案 (1)那就用命令git rm刪掉 git rm test06add.txt (2)並且git commit: git commit -m "first delete" (3)推送到遠端資料庫 git push 2.刪錯了 (1)
面試總結(3):執行緒(Thread)的同步以及sleep() 、wait()的區別
前言 這幾天忙一點私事,今天回來趕緊把面試總結接著寫下去,這次來看看Thread的join()方法和sleep()和wait()方法的區別。 正文 執行緒同步 上一篇提到了執行緒同步的問題,主要是通過鎖的形式來進行執行緒間的喚醒和等待,執行緒之間的
軟件架構設計學習總結(23):軟件架構設計的6大原則
str 軟件架構 edge 程序員 難點 posit not 幫我 mman 1. 單一職責原則(Single Responsibility Principle - SRP) 原文:There should never be more than one reason fo
機器學習總結(三):SVM支援向量機(面試必考)
基本思想:試圖尋找一個超平面來對樣本分割,把樣本中的正例和反例用超平面分開,並儘可能的使正例和反例之間的間隔最大。 演算法推導過程: (1)代價函式:假設正類樣本y =wTx+ b>=+1,負
老司機帶你玩轉面試(6):分散式鎖、併發競爭、雙寫一致
![](https://cdn.geekdigging.com/Interview/mianshi_header_1.jpg) ## 前文回顧 建議前面文章沒看過的同學先看下前面的文章: [「老司機帶你玩轉面試(1):快取中介軟體 Redis 基礎知識以及資料持久化」](https://www.geek
linux命令學習(6):ps命令
bytes 釋放 ice cti width kthread hellip 名稱 pts Linux中的ps命令是Process Status的縮寫。ps命令用來列出系統中當前運行的那些進程。ps命令列出的是當前那些進程的快照,就是執行ps命令的那個時刻的那些進程,如果想要
C++傳智筆記(6):socket客戶端發送報文接受報文的api接口
內存泄露 rcp 分配內存 strcpy light cpp tac 第三方 _file__ #define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" #include "string.
Windows Phone開發(6):處理屏幕方向的改變
cati sources mon stack mar ber XML break pac 俺們都知道,智能手機可以通過旋轉手機來改變屏幕的顯示方向,更多的時候,對於屏幕方向的改變,我們要做出相應的處理,例如,當手機屏幕方向從縱向變為橫向時,可能要重新排列頁面上的控件以適應顯
前端面試總結(css)
pan html元素 內容 brush bre 省略號 import als earlier 表格:Cellspacing:單元格間距,cellpadding:單元格內容之間的空隙,colspan:合並列數,rowspan:合並行數,表頭caption,border-sp
前端面試總結(JavaScript)
javascrip 類型 作用域鏈 word doc locals session jsonp 作用域 ajax優缺點 json和jsonP區別 省市聯動 全選 數組去重: 如何消除一個數組裏面重復的元素? // 方法一: var arr1 =[1,2,2,2,3,3,3
設計模式六大原則(6):開閉原則
思考 外部 編程人員 恰恰 單一職責 何事 適應 擴展 分享 開閉原則 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對
springBoot(6):web開發-模板引擎jsp
spring boot 一、新建工程 註意新建的工程下沒有webapp目錄eclipse下會自動創建webapp目錄這裏我們需要自動創建一個webapp目錄並創建WEB-INF。 對ServletInitializer.java進行說明 1、這個類相當於我們以前的web.xml 2、只有3.0以上才
學習用Node.js和Elasticsearch構建搜索引擎(6):實際項目中常用命令使用記錄
nds 黃色 ati cat htm action last shard open 1、檢測集群是否健康。 curl -XGET ‘localhost:9200/_cat/health?v‘#後面加一個v表示讓輸出內容表格顯示表頭 綠色表示一切正常,黃色表示所有
(轉)基於MVC4+EasyUI的Web開發框架經驗總結(6)--在頁面中應用下拉列表的處理
ica new web開發 don ext images 如果 bob 獲取 http://www.cnblogs.com/wuhuacong/p/3840321.html 在很多Web界面中,我們都可以看到很多下拉列表的元素,有些是固定的,有些是動態的;有些是字典內容,
EasyPR源碼剖析(6):車牌判斷之LBP特征
extend 順序 位置 feature tput ray bpf range str 一、LBP特征 LBP指局部二值模式,英文全稱:Local Binary Pattern,是一種用來描述圖像局部特征的算子,LBP特征具有灰度不變性和旋轉不變性等顯著優點。 原始的LBP
python函數(6):內置函數和匿名函數
a20 *args -s 執行 code str 思維導圖 inpu 其他 我們學了這麽多關於函數的知識基本都是自己定義自己使用,那麽我們之前用的一些函數並不是我們自己定義的比如說print(),len(),type()等等,它們是哪來的呢? 一、內置函數 由pytho
Tomcat學習總結(6)——Tomca常用配置詳解
mar evel 代碼段 between 取消 新建 unp -h tom 註:Tomcat 8需要JRE7以上的JRE 1. Tomcat環境變量設置 1.1 Java環境變量設置 右鍵計算機—屬性—高級系統設置—環境變量,在”系統環境變量”,設置如下三個變量(如果變量已
軟件架構設計學習總結(13):大型網站技術架構(七)網站的可擴展性架構
開放 擴展 修改 restfu 消息發送 封裝 nts 進行 可擴展性 擴展性是指對現有系統影響最小的情況下,系統功能可持續擴展或提升的能力。 設計網站可擴展架構的核心思想是模塊化,並在此基礎上,降低模塊間的耦合性,提供模塊的復用性。模塊通過分布式部署,獨立
軟件架構設計學習總結(14):大型網站技術架構(八)網站的安全架構
根據 知情 提交 pac 請求參數 用途 text 避免 信息加密 從互聯網誕生起,安全威脅就一直伴隨著網站的發展,各種Web攻擊和信息泄露也從未停止。常見的攻擊手段有XSS攻擊、SQL註入、CSRF、Session劫持等。 1、XSS攻擊 XSS攻擊即跨站點腳本攻擊(C