欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中實現(xiàn)多線程操作的幾種方式

 更新時間:2021年06月08日 10:43:48   作者:嘩啦啦啦啦  
多線程一直是一個老大難的問題,首先因為它難以理解,其次在實際工作中我們需要面對的關(guān)于線程安全問題也并不常見,今天就來總結(jié)一下實現(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)題欄漸變背景色的實例代碼

    這篇文章主要介紹了Android之scrollview滑動使標(biāo)題欄漸變背景色的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Android?Gradle同步優(yōu)化詳解

    Android?Gradle同步優(yōu)化詳解

    這篇文章主要為大家介紹了Android?Gradle同步優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Android的ListView多選刪除操作實現(xiàn)代碼

    Android的ListView多選刪除操作實現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android的ListView多選刪除操作實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android編程實現(xiàn)仿易信精美彈出框效果【附demo源碼下載】

    Android編程實現(xiàn)仿易信精美彈出框效果【附demo源碼下載】

    這篇文章主要介紹了Android編程實現(xiàn)仿易信精美彈出框效果,涉及Android窗口及動畫操作相關(guān)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下
    2017-01-01
  • Android中volley封裝實踐記錄

    Android中volley封裝實踐記錄

    這篇文章主要給大家介紹了關(guān)于Android中volley封裝實踐的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Android啟動頁用戶相關(guān)政策彈框的實現(xiàn)代碼

    Android啟動頁用戶相關(guān)政策彈框的實現(xiàn)代碼

    這篇文章主要介紹了Android啟動頁用戶相關(guān)政策彈框的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 查看 Android Studio NDK流程詳解

    查看 Android Studio NDK流程詳解

    這篇文章主要為大家介紹了查看 Android Studio NDK流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • MVVMLight項目的綁定及各種使用場景示例分析

    MVVMLight項目的綁定及各種使用場景示例分析

    這篇文章主要為大家介紹了MVVMLight項目中的綁定及綁定的各種使用場景示例源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步除夕快樂
    2022-01-01
  • Android使用AlertDialog實現(xiàn)對話框

    Android使用AlertDialog實現(xiàn)對話框

    本文主要介紹了Android使用AlertDialog實現(xiàn)對話框的相關(guān)知識,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • 詳談OnTouchListener與OnGestureListener的區(qū)別

    詳談OnTouchListener與OnGestureListener的區(qū)別

    下面小編就為大家?guī)硪黄斦凮nTouchListener與OnGestureListener的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04

最新評論