線程和線程池

線程

在java中實現線程的方式:javascript

  1. 繼承Thread類
  2. 實現Runable接口。

main方法其實也是一個線程。
在java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。java

  • 對比
    實現Runnable接口比繼承Thread類所具備的優點:
    1):適合多個相同的程序代碼的線程去處理同一個資源
    2):能夠避免java中的單繼承的限制
    3):增長程序的健壯性,代碼能夠被多個線程共享,代碼和數據獨立
  • yield()方法併發

    Thread.yield()方法做用是:暫停當前正在執行的線程對象,並執行其餘線程。
    yield()應該作的是讓當前運行線程回到可運行狀態,以容許具備相同優先級的其餘線程得到運行機會。所以,使用yield()的目的是讓相同優先級的線程之間能適當的輪轉執行。可是,實際中沒法保證yield()達到讓步目的,由於讓步的線程還有可能被線程調度程序再次選中。異步

    結論:yield()從未致使線程轉到等待/睡眠/阻塞狀態。在大多數狀況下,yield()將致使線程從運行狀態轉到可運行狀態,但有可能沒有效果。async

  • join()方法
    保證當前線程中止執行,直到該線程所加入的線程完成爲止,當前線程方可繼續執行。然而,若是它加入的線程沒有存活,則當前線程不須要中止。ide

AsyncTask

  • 內部由兩個線程池和一個Handler組成。
    1. SerialExecutor:用於任務的排隊,一次執行一個。
    2. ThreadPoolExecutor:用於真正的執行任務。
    3. InternalHandler:用於發送結果數據從子線程到主線程。
  • 執行流程:
    構造方法中實例化WorkerRunnable和FutureTask對象。
    WorkerRunnable將Params參數封裝,並將本身封裝在FutureTask中,一旦FutureTask執行run方法時,會去調用WorkRunnable的call方法並返回Result值。call方法中就執行了AsyncTask的doInBackground方法。並調用postResult方法將結果發送出去。oop

    mWorker = new WorkerRunnable<Params, Result>() {
      public Result call() throws Exception {
          mTaskInvoked.set(true);
    
          Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
          //noinspection unchecked
          Result result = doInBackground(mParams);
          Binder.flushPendingCommands();
          return postResult(result);
      }
    };
    
    private Result postResult(Result result) {
          @SuppressWarnings("unchecked")
          Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                  new AsyncTaskResult<Result>(this, result));
          message.sendToTarget();
          return result;
    }複製代碼

    那麼FutureTask是何時執行的?
    FutureTask充當了Runnable的做用,交給SerialExecutor的execute方法執行。FutureTask是一個併發類,能夠中途取消的用於異步計算的類。post

    SerialExecutor的execute方法首先把FutureTask插入到mTasks任務隊列中,若是沒有活動的任務,則執行下一個。當一個任務執行完成,會繼續調用scheduleNext方法執行下一個,直到全部任務都被執行。性能

    THREAD_POOL_EXECUTOR.execute(mActive);纔是真正執行任務的方法。使用的是ThreadPoolExecutor線程池。ui

    private static class SerialExecutor implements Executor {
      final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
      Runnable mActive;
    
      public synchronized void execute(final Runnable r) {
          //將FutureTask插入到mTasks任務隊列中
          mTasks.offer(new Runnable() {
              public void run() {
                  try {
                      // 執行FutureTask的run方法,進而執行call方法
                      r.run();
                  } finally {
                      // 串行執行下一個任務
                      scheduleNext();
                  }
              }
          });
          //沒有正在活動的任務,執行下一個AsyncTask。
          if (mActive == null) {
              scheduleNext();
          }
      }
    
      protected synchronized void scheduleNext() {
          if ((mActive = mTasks.poll()) != null) {
              THREAD_POOL_EXECUTOR.execute(mActive);
          }
      }
    }複製代碼
  • 注意:

    1. AsyncTask對象必須在主線程中建立
    2. execute必須在主線程中調用
    3. 一個AsyncTask只能調用一次execute方法,

HandlerThread

繼承了Thread類,本質仍是線程。可是能夠直接使用Handler的Thread。在run方法中經過Looper.prepare建立消息隊列,並開啓消息循環。使得能夠再次線程中建立Handler。

同時,它還解決了一個Looper與Handler的同步問題。能夠保證根據當前線程的Looper建立Handler時,Looper對象的獲取不爲空。
參考《深刻理解Android 卷I》159頁

/** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }複製代碼

因爲loop開啓了無限循環,所以能夠經過quit或者quitSafely方法終止線程執行。

典型應用場景就是在IntentService中。

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }複製代碼

IntentService

一個能夠處理異步請求的Service.服務開啓後,工做線程會依次處理每一個Intent,任務執行完畢後會自動關閉。

相對於線程而言,IntentService更適合執行一些高優先級的後臺任務。

@Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }複製代碼

線程池

  • 優勢
    1. 重用線程池中的線程,避免由於線程的建立和銷燬帶來的性能開銷。
    2. 有效控制線程的最大併發數,避免因大量的線程之間互相搶佔系統資源而致使的阻塞 。
    3. 可以對線程進行簡單的管理,並提供定時執行和執行循環間隔執行等功能
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {  }複製代碼
  • 變量

    • corePoolSize: 核心線程數
    • maximumPoolSize: 最大線程數
    • workQueue:任務隊列,提交的Runnable對象存儲在這裏。
    • keepAliveTime: 非核心線程存活時間
    • unit:keepAliveTime的時間單位。
    • threadFactory:爲線程池提供新線程的工廠。
    • handler:異常處理策略。
  • 規則

    1. 若是此時線程池中的數量小於corePoolSize,即便線程池中的線程都處於空閒狀態,也要建立新的線程來處理被添加的任務。
    2. 若是此時線程池中的數量等於 corePoolSize,可是緩衝隊列 workQueue未滿,那麼任務被放入緩衝隊列。
    3. 若是此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。
    4. 若是此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量等於maximumPoolSize,那麼經過 handler所指定的策略來處理此任務。
相關文章
相關標籤/搜索