Android中實現(xiàn)多線程操作的幾種方式
前言
多線程一直是一個老大難的問題,首先因為它難以理解,其次在實際工作中我們需要面對的關(guān)于線程安全問題也并不常見,今天就來總結(jié)一下實現(xiàn)多線程的幾種方式,可能并不全面,還請各位看官多多補充。
最基礎(chǔ)的方式
繼承Thread類并實現(xiàn)run()方法
class MyThread extends Thread{ @Override public void run() { System.out.println("我是子線程"); } } new MyThread().start();
匿名內(nèi)部類
public class ManyThread { public static void main(String[] args) { new Thread(){ public void run() { System.out.println("我是子線程"); }; }.start(); } }
實現(xiàn)Runnable接口
class MyRunnable implements Runnable{ @Override public void run() { System.out.println("我是子線程"); } } Thread thread = new Thread(new MyRunnable()); thread.start();
太簡單了吧!!別著急,這只是熱身~
callable+FutureTask
Callable接口類似于Runnable,區(qū)別在于使用callable可以拿到結(jié)果。
FutureTask實現(xiàn)了RunnableFuture,
public class FutureTask<V> implements RunnableFuture<V> { ... }
RunnableFuture又實現(xiàn)了Runnable和Future
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
所以FutureTask既可以當(dāng)Runnable使用又可以當(dāng)Future使用get()來拿到結(jié)果
future的API:get():當(dāng)任務(wù)結(jié)束后,返回一個結(jié)果,如果調(diào)用時,任務(wù)還沒有結(jié)束,則會阻塞線程,直到任務(wù)執(zhí)行完畢??梢栽O(shè)置等待時間,超出時間或者返回結(jié)果為null,則拋出異常cancel():
//自定義CallAble并實現(xiàn)call()方法 class MyCallable implements Callable<Integer>{ @Override public Integer call() throws Exception { int a = 1; for (int i = 0; i <100000; i++) { a++; } Thread.sleep(2000); return a; } } public static void main(String[] args) { //新建CallAble MyCallable callable = new MyCallable(); //新建FutureTask任務(wù) FutureTask<Integer> futureTask = new FutureTask<Integer>(callable); //新建Thread并與FutureTask關(guān)聯(lián) Thread thread = new Thread(futureTask, "A"); thread.start(); int sum; try { //拿到callable的結(jié)果 sum = futureTask.get(); System.out.println(sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
線程池
線程池的創(chuàng)建方式有兩種,
手動創(chuàng)建線程池
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
要注意線程池的幾個參數(shù):
- corePoolSize :核心線程數(shù)
- maximumPoolSize :允許創(chuàng)建的最大線程數(shù)
- keepAliveTime :這是空閑線程保持存活的最大時間。
- unit : keepAliveTime的時間單位
- workQueue :任務(wù)隊列,保存等待執(zhí)行的任務(wù)的阻塞隊列
- threadFactory :用于設(shè)置創(chuàng)建線程的工廠,可以通過線程工廠給每個創(chuàng)建出來的線程設(shè)置更有含義的名字
- handler :飽和策略,當(dāng)隊列和線程池都滿了,說明線程處于飽和狀態(tài),必須采取一種策略處理提交的新任務(wù)。默認(rèn)情況下是AbortPolicy,表示無法處理新任務(wù)時拋出異常。
向線程池提交任務(wù)execute()和submit():
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()); //使用execute提交任務(wù) threadPoolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("我是線程池"); } }); //之前說的callable MyCallable callable = new MyCallable(); //使用submit提交任務(wù) 返回一個future Future<Integer> future = threadPoolExecutor.submit(callable); try { //通過future拿到執(zhí)行callable的結(jié)果 int x = future.get(); System.out.println(x); } catch (InterruptedException e) { //中斷異常 e.printStackTrace(); } catch (ExecutionException e) { //無法執(zhí)行任務(wù)異常 e.printStackTrace(); }finally { //關(guān)閉線程池 threadPoolExecutor.shutdown(); }
使用自定義線程池要合理的配置各個參數(shù)。
- 根據(jù)任務(wù)的性質(zhì):CPU密集型還是IO密集型設(shè)置核心線程數(shù)的大小,cpu密集型應(yīng)配置盡可能小的線程,可以配置為 CPU個數(shù)+1。由于IO密集型任務(wù)線程并不是一直在執(zhí)行任務(wù),應(yīng)配置盡可能多的線程,可以配置為 2*cpu個數(shù)
- 優(yōu)先級不同的任務(wù),可以使用優(yōu)先級隊列PriorityBlockingQueue來處理,它可以讓優(yōu)先級高的任務(wù)先執(zhí)行
- 建議使用有界隊列,有界隊列能增加系統(tǒng)的穩(wěn)定性和預(yù)警能力。
使用Executors創(chuàng)建線程池
這種創(chuàng)建方式本質(zhì)上也是對ThreadPoolExecutor的參數(shù)進(jìn)行不同的配置,每條創(chuàng)建后邊把源碼中不同的配置放到后邊,以便更清晰的展示出來
//會根據(jù)需要創(chuàng)建新線程的線程池 ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); //核心線程數(shù)設(shè)置為0,最大線程數(shù)則是無界,的也就是說某些情況下會有無限多的線程被創(chuàng)建,從而導(dǎo)致一些問題,空閑線程最大等待時長是60秒 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } //使用單個worker線程 ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor(); //核心線程數(shù)和最大線程數(shù)都設(shè)置為1,并使用無界隊列作為線程池的工作隊列,其容量為無限大,某些情況下會導(dǎo)致隊列中有太多的任務(wù)而出錯 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } //可重用固定線程數(shù)的線程池 ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10); //核心線程數(shù)和最大線程數(shù)都設(shè)置為創(chuàng)建時傳入的數(shù)量,空閑等待時長為0,說明空閑線程會立即終止,而任務(wù)隊列容量也是無限大,可能會導(dǎo)致同樣的問題 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } //可以用來在給定延時后執(zhí)行異步任務(wù)或者周期性執(zhí)行任務(wù) ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2); //核心線程的個數(shù)為指定的數(shù)量,允許的最大線程數(shù)是無限的 public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler); }
Android中特有的實現(xiàn)多線程
使用HandlerThread
HandleThread本質(zhì)上就是一個線程,其繼承了Thread。它的內(nèi)部有自己的looper對象,并在run方法中通過Looper.prepare()來創(chuàng)建消息隊列,并通過Looper.loop()開啟消息循環(huán),這樣在使用中就允許在HandlerThread中創(chuàng)建Handler了
HandlerThread和普通的Thread是有顯著的區(qū)別的,普通的Thread主要在run方法中執(zhí)行一個耗時任務(wù),而HandlerThread在內(nèi)部創(chuàng)建了消息隊列,外界需要通過Handler的消息方式來通知HandlerThread執(zhí)行一個具體的任務(wù),由于handlerThread的run方法是一個無限循環(huán),因此當(dāng)明確不需要再使用HandlerThread時,可以通過其quit或者quitSafely方法來終止線程的執(zhí)行。
public class HandlerThread extends Thread { Looper mLooper; private @Nullable Handler mHandler; @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } ... }
具體使用:
//創(chuàng)建handlerThread,標(biāo)記一個名字 HandlerThread handlerThread = new HandlerThread("MyHandlerThread"); //啟動線程 handlerThread.start(); //創(chuàng)建工作線程的handler,關(guān)聯(lián)handlerThread的Looper對象。 //復(fù)寫handleMessage處理消息 Handler myHandler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { Log.i(msg.what + msg.obj.toString()); super.handleMessage(msg); } }; //定義消息 Message msg = new Message(); msg.what = 1; msg.obj = "A"; //發(fā)送消息到其綁定的消息隊列中 myHandler.sendMessage(msg); //結(jié)束線程,停止線程的消息循環(huán) handlerThread.quit();
使用IntentService
本質(zhì)上是一個Service,可以看做是Service和HandlerThread的結(jié)合體,它繼承了Service并且是一個抽象類,因此需要創(chuàng)建它的子類才能使用IntentService??梢杂糜趫?zhí)行后臺耗時任務(wù),由于是服務(wù),所以它的優(yōu)先級比單純的線程要高很多,并且不容易被系統(tǒng)殺死。有如下幾個特點
- IntentService是繼承自service并處理異步請求的一個類,其內(nèi)部有一個工作線程處理耗時請求
- 任務(wù)執(zhí)行完畢,會自動銷毀
- 如果IntentService啟動多次,每個耗時操作會以隊列的方式在IntentService的onHandleIntent方法中依次執(zhí)行,串行執(zhí)行結(jié)束后,會自動銷毀。
首先看一下IntentService的源碼:
//繼承自service public abstract class IntentService extends Service { private volatile Looper mServiceLooper; @UnsupportedAppUsage private volatile ServiceHandler mServiceHandler; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { //處理消息時調(diào)用onHandleIntent方法 我們需要重寫這個方法實現(xiàn)自己的處理邏輯 onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } ... @Override public void onCreate() { super.onCreate(); //創(chuàng)建handlerThread并啟動 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); //初始化handler并綁定handlerThread的looper mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; //通過handler發(fā)送消息給HandlerThread處理 mServiceHandler.sendMessage(msg); } ...
當(dāng)IntentService被啟動時,它的onCreate方法被調(diào)用,onCreate方法會創(chuàng)建一個HandlerThread,然后使用它的Looper來構(gòu)造一個Handler對象,這樣通過Handler發(fā)送的消息最終會在HandlerThread中執(zhí)行。每次啟動IntentService,它的onStartCommand方法就會調(diào)用一次,IntentService在onStartCommand中處理每個后臺任務(wù)的Intnet。onStartCommond調(diào)用了onStart,在onStart方法中,IntentService通過handler發(fā)送一個消息,這個消息會在HandlerThread中處理。當(dāng)onHandleIntent方法執(zhí)行結(jié)束后,IntentService會通過stopSelf方法嘗試停止服務(wù),onHandlerIntent是一個抽象方法,需要我們在子類中實現(xiàn),它的作用是從Intent參數(shù)中區(qū)分具體的任務(wù)并執(zhí)行這些任務(wù)。
如何使用?
- 新建service類并繼承自IntentService
- 實現(xiàn)service的構(gòu)造方法
- 在manifast.xml中注冊服務(wù)
- 在服務(wù)的onHandleIntent方法中實現(xiàn)業(yè)務(wù)邏輯
自定義一個IntentService
public class MyIntentService extends IntentService { public MyIntentService(String name) { super(name); } @Override protected void onHandleIntent(@Nullable Intent intent) { if(intent != null){ String action = intent.getAction(); if(action.equals("A")){ doSomeThingA(); }else if(action.equals("B")){ doSomeThingB(); } } } }
JobIntentService/JobScheduler
系統(tǒng)不允許后臺應(yīng)用創(chuàng)建后臺服務(wù),因此8.0引入了Context.startForegroundService(),以在前臺啟動新服務(wù),
由于Android O的后臺限制,創(chuàng)建后臺服務(wù)需要使用JobScheduler來由系統(tǒng)進(jìn)行調(diào)度任務(wù)的執(zhí)行,而使用JobScheduler的方式比較繁瑣,8.0及以上提供了JobIntentService幫助開發(fā)者更方便的將任務(wù)交給JobScheduler調(diào)度,其本質(zhì)是Service后臺任務(wù)在他的OnhandleWork()中進(jìn)行,子類重寫該方法即可。使用較簡單。
public class SimpleJobIntentService extends JobIntentService { /** * 這個Service 唯一的id */ static final int JOB_ID = 1000; /** * 將工作加入此服務(wù)的方法,使用中調(diào)用這個方法 */ static void enqueueWork(Context context, Intent work) { enqueueWork(context, SimpleJobIntentService.class, JOB_ID, work); } //在這里執(zhí)行耗時任務(wù) @Override protected void onHandleWork(Intent intent) { Log.i("SimpleJobIntentService", "Executing work: " + intent); String label = intent.getStringExtra("label"); if (label == null) { label = intent.toString(); } toast("Executing: " + label); for (int i = 0; i < 5; i++) { Log.i("SimpleJobIntentService", "Running service " + (i + 1) + "/5 @ " + SystemClock.elapsedRealtime()); try { Thread.sleep(1000); } catch (InterruptedException e) { } } Log.i("SimpleJobIntentService", "Completed service @ " + SystemClock.elapsedRealtime()); } @Override public void onDestroy() { super.onDestroy(); toast("All work complete"); } final Handler mHandler = new Handler(); // Helper for showing tests void toast(final CharSequence text) { mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(SimpleJobIntentService.this, text, Toast.LENGTH_SHORT).show(); } }); } }
activity中通過調(diào)用enqueueWork()方法來啟動
Intent workIntent = new Intent(); num++; Log.d("houson", "onClick: "+num); workIntent.putExtra("work","work num:"+num); //調(diào)用enqueueWork方法 MyJobIntentService.enqueueWork(getApplicationContext(),workIntent);
WorkManager
根據(jù)需求的不同,Android為后臺任務(wù)提供了多種解決方案,如JobScheduler,Loader,Service等。如果這些API沒有被適當(dāng)?shù)厥褂?,可能會消耗大量的電量。WorkManager的出現(xiàn),為應(yīng)用程序中那些不需要及時完成的任務(wù),提供統(tǒng)一的解決方案,以便在設(shè)備電量和用戶體驗之間達(dá)到一個比較好的平衡。
WorkManager最低可以兼容API Level 14,在API Level 23+,通過JobScheduler來完成任務(wù),23一下的設(shè)備,通過AlarmManager和BroadCastReceivers組合完成任務(wù)。
WorkManager主要針對不需要及時完成的任務(wù),如發(fā)送日志,同步應(yīng)用程序數(shù)據(jù),備份等。并且可以保證任務(wù)一定會被執(zhí)行,即使應(yīng)用當(dāng)前不在運行中,WorkManager有自己的數(shù)據(jù)庫,關(guān)于任務(wù)的所有信息和數(shù)據(jù)都保存在這個數(shù)據(jù)庫中。因此只要你的任務(wù)交給了WorkManager,哪怕你的應(yīng)用程序徹底退出,或者設(shè)備重新啟動,WorkManager依然能夠保證完成你交給的任務(wù)。
如何使用?
添加依賴
dependencies { def versions = "2.2.0" implementation "androidx.work:work-runtime:$versions" }
定義Worker任務(wù):
worker是任務(wù)的執(zhí)行者,是一個抽象類,需要繼承它實現(xiàn)要執(zhí)行的任務(wù)。
//繼承worker,自定義worker class MyWork extends Worker{ public MyWork(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } //執(zhí)行耗時任務(wù) @NonNull @Override public Result doWork() { //拿到傳進(jìn)來的數(shù)據(jù) String input_data = getInputData().getString("input_data"); // 任務(wù)執(zhí)行完成后返回數(shù)據(jù) Data outputData = new Data.Builder().putString("output_data", "Success!").build(); // 執(zhí)行成功返回Result.success() // 執(zhí)行失敗返回Result.failure() // 需要重新執(zhí)行返回Result.retry() return Result.success(outputData); } }
使用WorkRequest配置任務(wù)。
WorkRequest指定讓哪個 Woker 執(zhí)行任務(wù),指定執(zhí)行的環(huán)境,執(zhí)行的順序等。要使用它的子類 OneTimeWorkRequest(執(zhí)行一次) 或 PeriodicWorkRequest(周期執(zhí)行)。
通過WorkRequest配置我們的任務(wù)何時運行以及如何運行
//設(shè)置任務(wù)的觸發(fā)條件 Constraints constraints = new Constraints.Builder() .setRequiresCharging(true) // 在充電時執(zhí)行 .setRequiresStorageNotLow(true) // 不在存儲容量不足時執(zhí)行 // 網(wǎng)絡(luò)狀態(tài) //NOT_REQUIRED--沒有要求 //CONNECTED--網(wǎng)絡(luò)連接 //UNMETERED--連接無限流量的網(wǎng)絡(luò) //METERED--連接按流量計費的網(wǎng)絡(luò) //NOT_ROAMING--連接非漫游網(wǎng)絡(luò) .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresDeviceIdle(true) // 在待機狀態(tài)下執(zhí)行,需要 API 23 .setRequiresBatteryNotLow(true)// 不在電量不足時執(zhí)行 .build(); //然后將該Constraints設(shè)置到WorkRequest。WorkRequest是一個抽象類, //它有兩種實現(xiàn)OneTimeWorkRequest和PeriodicWorkRequest,分別對應(yīng)的是一次性任務(wù)和周期性任務(wù)。 //定義要傳遞的數(shù)據(jù) Data inputData = new Data.Builder().putString("input_data", "Hello").build(); OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setConstraints(constraints) .setInputData(inputData) .build();
WorkManager
將任務(wù)提交給系統(tǒng)。管理任務(wù)請求和任務(wù)隊列,發(fā)起的 WorkRequest 會進(jìn)入它的任務(wù)隊列。WorkManager.enqueue()方法會將你配置好的WorkRequest交給系統(tǒng)來執(zhí)行。
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest);
觀察任務(wù)的狀態(tài)
任務(wù)在提交給系統(tǒng)后,通過WorkInfo獲知任務(wù)的狀態(tài),WorkInfo包含了任務(wù)的id,tag,以及Worker對象傳遞過來的outputData,以及任務(wù)當(dāng)前的狀態(tài)。有三種方式可以得到WorkInfo對象。
通過LiveData,我們便可以在任務(wù)狀態(tài)發(fā)生變化的時候,收到通知。同時通過LiveData的WorkInfo.getOutputData(),得到從Worker傳遞過來的數(shù)據(jù)。
WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.getId()).observe( MainActivity.this, new Observer<WorkInfo>() { @Override public void onChanged(WorkInfo workInfo) { Log.d("onChanged()->", "workInfo:"+workInfo); if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) { String outputData = workInfo.getOutputData().getString("output_data"); Log.d("onChanged()->", "outputData:"+outputData); } } } );
取消任務(wù)
WorkManager.getInstance(MainActivity.this).cancelAllWork();
以上就是WorkManager的一些基本使用,更詳細(xì)的可以參照官方文檔或者其他文章,這里就不仔細(xì)講解了。工作中,我們經(jīng)常需要處理后臺任務(wù),如果處理后臺任務(wù)所采用的API沒有被正確使用,那么很可能會消耗大量設(shè)備的電量。Android出于設(shè)備電量的考慮,為開發(fā)者提供了WorkManager,旨在將一些不需要及時完成的任務(wù)交給它來完成。
使用協(xié)程
協(xié)程是一種并發(fā)設(shè)計模式,您可以在 Android 平臺上使用它來簡化異步執(zhí)行的代碼,協(xié)程是輕量級的線程,為什么是輕量的?因為它基于線程池API。協(xié)程可以使用阻塞式的方式寫出非阻塞式的代碼,解決回調(diào)地獄的問題。
協(xié)程有如下的特點:
- 輕量:您可以在單個線程上運行多個協(xié)程,因為協(xié)程支持掛起,不會使正在運行協(xié)程的線程阻塞。掛起比阻塞節(jié)省內(nèi)存,且支持多個并行操作。
- 內(nèi)存泄漏更少:使用結(jié)構(gòu)化并發(fā)機制在一個作用域內(nèi)執(zhí)行多項操作。
- 內(nèi)置取消支持:取消操作會自動在運行中的整個協(xié)程層次結(jié)構(gòu)內(nèi)傳播。
- Jetpack 集成:許多 Jetpack 庫都包含提供全面協(xié)程支持的擴展。某些庫還提供自己的協(xié)程作用域,可供您用于結(jié)構(gòu)化并發(fā)。
引入?yún)f(xié)程
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") }
使用
fun main() = runBlocking { launch { delay(1000L) println("World!") } println("Hello") }
協(xié)程的使用當(dāng)然不是這么簡單,有很多的API,這里限于篇幅,就不深入講解了。
AsyncTask
是一個輕量級的異步任務(wù)類,在高版本中已經(jīng)過時了。但研究一下還是很有意義的。他可以在線程池中執(zhí)行后臺任務(wù),然后把執(zhí)行的進(jìn)度和最終結(jié)果傳遞給主線程并在主線程中更新ui。AsyncTask封裝了Thread和Handler,通過AsyncTask可以更加方便的執(zhí)行后臺任務(wù)以及在主線程中訪問ui。
AsyncTask提供了四個核心方法:
- onPreExecute:在主線程中執(zhí)行,在異步任務(wù)執(zhí)行之前,此方法會被調(diào)用,一般用于一些準(zhǔn)備工作
- doInBackground:在線程池中執(zhí)行,此方法用于執(zhí)行異步任務(wù),params參數(shù)表示異步任務(wù)的輸入?yún)?shù),此方法中可以通過publishProgress來更新任務(wù)的進(jìn)度。
- onProgressUpdata(Progress...values):在主線程中執(zhí)行,當(dāng)后臺任務(wù)的執(zhí)行進(jìn)度發(fā)生改變時調(diào)用此方法
- onPostExecute:在主線程中執(zhí)行,在異步任務(wù)執(zhí)行之后,此方法會被調(diào)用,result參數(shù)是后臺任務(wù)的返回值,即doInbackground的返回值
AsyncTask在使用過程中有一些限制條件:
- AsyncTask必須在主線程中加載,也就是第一次訪問AsyncTask必須發(fā)生在主線程
- AsyncTask的對象須在主線程中創(chuàng)建
- execute方法必須在ui線程調(diào)用
- 不要在程序中直接調(diào)用onPreExecute、onPostExecute、doInBackground、onProgressUpdate方法
- 一個AsyncTask對象只能執(zhí)行一次,也就是只能調(diào)用一次execute方法,否則會報異常
原理分析:
從execute方法開始分析,調(diào)用executeOnExecutor方法,sDefaultExecutor是一個串行的線程池如下:
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; //線程池開始執(zhí)行 封裝為Futuretask交個線程池處理 exec.execute(mFuture); return this; }
sDefaultExecutor是一個串行線程池,一個進(jìn)程中所有的AsyncTask任務(wù)都在這個線程池中排隊執(zhí)行。首先系統(tǒng)會把AsyncTask的Params參數(shù)封裝為FutureTask對象,這里FutureTask充當(dāng)Runnable,接著這個FutureTask會交給SerialExecutor的execute方法處理,SerialExecute的execute方法首先把FutureTask對象插入到任務(wù)隊列中,接著調(diào)用scheduleNext方法執(zhí)行FutureTask任務(wù),從隊列中取出任務(wù)交給THREAD_POOL_EXECUTOR線程池去真正執(zhí)行任務(wù)。InternalHandler用于將執(zhí)行環(huán)境從線程池切換到主線程。
//串行線程池 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //線程池用于真正執(zhí)行任務(wù) public static final Executor THREAD_POOL_EXECUTOR; //用于將執(zhí)行環(huán)境從線程池切換到主線程 private static InternalHandler sHandler; //初始化執(zhí)行任務(wù)的線程池 static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor; } //用于調(diào)度任務(wù)的串行線程池 private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { //從隊列中取出任務(wù)交個THREAD_POOL_EXECUTOR線程池去真正執(zhí)行任務(wù) if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
再看一下任務(wù)future,call方法中調(diào)用postResult方法,通過handler發(fā)送消息,最終在handleMessage方法中進(jìn)行處理。
private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } };
結(jié)語
以上介紹了幾種實現(xiàn)多線程操作的方式,有些并沒有深入分析,當(dāng)然了,實現(xiàn)多線程的方式不止以上的幾種,還請各位看官多多補充,如有錯誤的地方還請指出。
到此這篇關(guān)于Android中實現(xiàn)多線程操作的幾種方式的文章就介紹到這了,更多相關(guān)Android多線程操作 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android之scrollview滑動使標(biāo)題欄漸變背景色的實例代碼
這篇文章主要介紹了Android之scrollview滑動使標(biāo)題欄漸變背景色的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05Android的ListView多選刪除操作實現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android的ListView多選刪除操作實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-05-05Android編程實現(xiàn)仿易信精美彈出框效果【附demo源碼下載】
這篇文章主要介紹了Android編程實現(xiàn)仿易信精美彈出框效果,涉及Android窗口及動畫操作相關(guān)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-01-01Android啟動頁用戶相關(guān)政策彈框的實現(xiàn)代碼
這篇文章主要介紹了Android啟動頁用戶相關(guān)政策彈框的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05Android使用AlertDialog實現(xiàn)對話框
本文主要介紹了Android使用AlertDialog實現(xiàn)對話框的相關(guān)知識,具有很好的參考價值。下面跟著小編一起來看下吧2017-03-03詳談OnTouchListener與OnGestureListener的區(qū)別
下面小編就為大家?guī)硪黄斦凮nTouchListener與OnGestureListener的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04