本文主要使用kotlin,,討論Android開發(fā)中的線程池用法,。 我們想使用線程的時(shí)候,可以直接創(chuàng)建子線程并啟動(dòng) Thread { Log.d("rfDev", "rustfisher said: hello") }.start()
遇到這樣的情況,我們可以考慮線程池,。線程池解決兩個(gè)問題:需要執(zhí)行大量異步任務(wù)的時(shí)候,,減輕每個(gè)異步任務(wù)的調(diào)用開銷,提高性能,。另外它還能夠限制和管理子線程,。每個(gè)ThreadPoolExecutor都維護(hù)了一些統(tǒng)計(jì)數(shù)據(jù),例如已執(zhí)行的任務(wù)數(shù)量,。 有大量異步任務(wù)的時(shí)候,,可以考慮使用線程池。 預(yù)置線程池#
ThreadPoolExecutor提供了很多參數(shù),,方便開發(fā)者調(diào)控,。線程池的設(shè)計(jì)者建議開發(fā)者使用以下幾個(gè)工廠方法,Android中主要有5種
實(shí)際上我們?cè)贏ndroid Studio里輸入 Executors.new 的智能提示 可緩存線程池#用 val tp: ExecutorService = Executors.newCachedThreadPool()tp.submit { Log.d(TAG, "rustfisher: cached線程池執(zhí)行任務(wù) 3") } 可緩存線程池會(huì)在需要的時(shí)候創(chuàng)建新的子線程,。當(dāng)原有的線程可用的時(shí)候,,會(huì)復(fù)用現(xiàn)有線程。 調(diào)用 定長(zhǎng)線程池#使用 val fixedTp: ExecutorService = Executors.newFixedThreadPool(4)fixedTp.submit { Log.d(TAG, "rustfisher 定長(zhǎng)線程池執(zhí)行任務(wù)") } 靜態(tài)方法里傳入了一個(gè)int參數(shù) 如果有的線程遇到錯(cuò)誤而停止了,要執(zhí)行任務(wù)的話,,會(huì)創(chuàng)建新的線程補(bǔ)上位置,。 池里的線程會(huì)一直存活,直到線程池停止( 單一線程池#val singleTp: ExecutorService = Executors.newSingleThreadExecutor()singleTp.submit { Log.d(TAG, "單一線程池執(zhí)行任務(wù)") } 只擁有1個(gè)子線程,。任務(wù)隊(duì)列不限制任務(wù)數(shù)量。如果線程遇到問題停止了,,接下來又要處理任務(wù)時(shí),,會(huì)新建一個(gè)線程來處理。 它能保證任務(wù)會(huì)按順序處理,,同一時(shí)間只能處理1個(gè)任務(wù),。 單一線程池創(chuàng)建后,不能動(dòng)態(tài)修改線程數(shù)量,。不像 計(jì)劃任務(wù)線程池#val scheduleTp: ScheduledExecutorService = Executors.newScheduledThreadPool(3) 計(jì)劃任務(wù)線程池能夠執(zhí)行延遲任務(wù)和周期任務(wù)。 延遲任務(wù)#需要設(shè)定延時(shí)與時(shí)間單位 scheduleTp.schedule({ Log.d(TAG, "計(jì)劃任務(wù)1 runnable") }, 300, TimeUnit.MILLISECONDS)scheduleTp.schedule(Callable { Log.d(TAG, "計(jì)劃任務(wù)2 callable") }, 400, TimeUnit.MILLISECONDS) 周期任務(wù)#主要涉及到2個(gè)方法 假設(shè)任務(wù)時(shí)間小于周期時(shí)間,,則按給定周期時(shí)間來進(jìn)行。這兩個(gè)方法表現(xiàn)一致,。 假設(shè)任務(wù)執(zhí)行時(shí)間大于周期時(shí)間,,這兩個(gè)方法有點(diǎn)不同
工作竊取線程池#Android SDK 大于等于24,有一種新的線程池,,暫且稱為“工作竊取線程池”,,或者叫“靈活調(diào)度線程池”。 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { Executors.newWorkStealingPool()} 線程池維護(hù)足夠的線程來支持給定的并行度(parallelism level),,可能會(huì)用多個(gè)隊(duì)列來減少爭(zhēng)用,。 線程的實(shí)際數(shù)量可能會(huì)動(dòng)態(tài)增減,。工作竊取線程池不保證按提交順序來處理任務(wù),。 執(zhí)行任務(wù)#執(zhí)行任務(wù)的時(shí)候可以傳入Runnable和Callable,前面用的都是Runnable,。 用Callable的例子 tp.submit(Callable { "OK" }) 無返回值任務(wù)的調(diào)用#無返回值任務(wù)用Callable和Runnable都行,。 val tp: ExecutorService = Executors.newCachedThreadPool()tp.submit { Log.d(TAG, "rustfisher: cached線程池submit runnable") }tp.execute { Log.d(TAG, "rustfisher: cached線程池execute runnable") }tp.submit(Callable { Log.d(TAG, "rustfisher: cached線程池submit callable") })tp.shutdown() // 最后記得用完后停掉線程池 有返回值任務(wù)的調(diào)用#有返回值的任務(wù)需要Callable接口。 submit#調(diào)用 val tp: ExecutorService = Executors.newCachedThreadPool()val future = tp.submit(Callable { return@Callable "callable的返回值"})Log.d(TAG, "future get之前 isDone: ${future.isDone}, isCancelled: ${future.isCancelled}")val res = future.get()Log.d(TAG, "future get之后 isDone: ${future.isDone}, isCancelled: ${future.isCancelled}")Log.d(TAG, "future get: $res") 運(yùn)行l(wèi)og future get之前 isDone: false, isCancelled: falsefuture get之后 isDone: true, isCancelled: falsefuture get: callable的返回值 invokeAll#對(duì)于列表里的任務(wù),可以使用 invokeAll示例 val tp: ExecutorService = Executors.newFixedThreadPool(5) val callList = arrayListOf<Callable<String>>( Callable { Log.d(TAG, "task1 ${Thread.currentThread()}") return@Callable "rust" }, Callable { Log.d(TAG, "task2 ${Thread.currentThread()}") Thread.sleep(1500) // 加上延時(shí) return@Callable "fisher" }, Callable { Log.d(TAG, "task3 ${Thread.currentThread()}") return@Callable "列表里面的任務(wù)" }, ) Log.d(TAG, "invokeAll 準(zhǔn)備提交任務(wù)") val futureList = tp.invokeAll(callList) Log.d(TAG, "invokeAll 已提交任務(wù)") futureList.forEach { f -> Log.d(TAG, "任務(wù)列表執(zhí)行結(jié)果 ${f.get()}") // 這里會(huì)阻塞 別在ui線程里get } 運(yùn)行l(wèi)og,,可以看到提交任務(wù)后,經(jīng)過延時(shí),,拿到了運(yùn)行結(jié)果,。注意看 2021-09-11 14:40:07.062 16914-16914/com.rustfisher.tutorial2020 D/rfDevTp: invokeAll 準(zhǔn)備提交任務(wù) 2021-09-11 14:40:07.063 16914-19230/com.rustfisher.tutorial2020 D/rfDevTp: task1 Thread[pool-4-thread-1,5,main] 2021-09-11 14:40:07.063 16914-19231/com.rustfisher.tutorial2020 D/rfDevTp: task2 Thread[pool-4-thread-2,5,main] 2021-09-11 14:40:07.063 16914-19232/com.rustfisher.tutorial2020 D/rfDevTp: task3 Thread[pool-4-thread-3,5,main] 2021-09-11 14:40:08.563 16914-16914/com.rustfisher.tutorial2020 D/rfDevTp: invokeAll 已提交任務(wù) 2021-09-11 14:40:08.563 16914-16914/com.rustfisher.tutorial2020 D/rfDevTp: 任務(wù)列表執(zhí)行結(jié)果 rust 2021-09-11 14:40:08.563 16914-16914/com.rustfisher.tutorial2020 D/rfDevTp: 任務(wù)列表執(zhí)行結(jié)果 fisher 2021-09-11 14:40:08.563 16914-16914/com.rustfisher.tutorial2020 D/rfDevTp: 任務(wù)列表執(zhí)行結(jié)果 列表里面的任務(wù) 提交了3個(gè)任務(wù),,在3個(gè)不同的子線程中執(zhí)行,。 invokeAny#
invokeAny示例 val tp: ExecutorService = Executors.newCachedThreadPool() val callList = arrayListOf<Callable<String>>( Callable { Thread.sleep(1000) // 設(shè)計(jì)延時(shí) return@Callable "rust" }, Callable { Thread.sleep(400) return@Callable "fisher" }, Callable { Thread.sleep(2000) return@Callable "列表里面的任務(wù)" }, ) Log.d(TAG, "invokeAny 提交任務(wù)") val res = tp.invokeAny(callList) Log.d(TAG, "執(zhí)行結(jié)果 $res") 2021-09-11 14:04:55.253 14066-14066/com.rustfisher.tutorial2020 D/rfDevTp: invokeAny 提交任務(wù) 2021-09-11 14:04:55.654 14066-14066/com.rustfisher.tutorial2020 D/rfDevTp: 執(zhí)行結(jié)果 fisher 觀察log可以看到,最后執(zhí)行的是“fisher”這個(gè)任務(wù),。 停止線程池#使用完畢后,記得終止線程池 /*ExecutorService*/ shutdown()shutdownNow()
|
|