android中的線程使用與通信機制

1、android的所有應用程序組件,包括Activity、Service和BroadcastReceiver都在應用程序的主線程中執行,所有的耗時處理都可能阻塞其他組件,所以所有的耗時處理和IO操作都應該從主線程移到一個子線程中。常見的如:文件操作、網絡查找、數據庫事務和耗時複雜計算。
2、關於Android ANR,android系統規定,Activity對於一個輸入事件(例如,按下一個按鍵)在5s的時間內沒有響應,或者broadcast receiver在10s內沒有完成對於onReceiver的處理。這是系統將認定爲ANR,彈出提示框。
3、關於後臺線程的幾種方式:下面主要介紹下。

關於AsyncTask:
具體細節和使用方法了,詳見android官方文檔。http://developer.android.com/reference/android/os/AsyncTask.html
這裏談一下需要注意的事項:
每個AsyncTask實例只能被執行一次,如果試圖第二次調用excute,則會拋出異常!
需要注意的是:當Activity重新啓動時,操作將不會持續進行。AsyncTask在設備的方向變化而導致Activity被銷燬和重新創建時會被取消。
AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as ExecutorThreadPoolExecutor and FutureTask.
官方提示,至多幾秒鐘,需要長期運行的,建議使用java.util.concurrent包!

  • The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
  • AsyncTask類必須在UI線程被加載
  • The task instance must be created on the UI thread.
  • 類實例必須被在UI線程創建
  • execute(Params...) must be invoked on the UI thread.
  • execute方法必須在UI線程被調用
  • Do not   call onPreExecute()onPostExecute(Result)doInBackground(Params...)onProgressUpdate(Progress...) manually.
  • 不要顯式調用這些方法
  • The task can be executed only once (an exception will be thrown if a second execution is attempted.)
  • 任務只能被執行一次,第二次被執行就會拋出異常。
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
自從android3.2版本開始,AsyncTask不再爲每個AsyncTask的實例單獨創建一個線程,相反,它使用一個excutor在單一的後臺線程上運行所有的AsyncTask後臺任務,這就意味着每個實例其實都是排隊逐個運行的,顯然,長時間運行的AsyncTask會阻塞其他的AsyncTask
這個讓我感到非常困惑,這段話是developer上的官方文檔,但是我去看了下源碼,   明明是使用線程池的啊,   
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
當前的可用的核心數,由於很多移動設備會關閉無關核心以達到省電的目的,所以,可能大多數情況下都是1吧,只能暫時這麼理解了。
public static final Executor THREAD_POOL_EXECUTOR new ThreadPoolExecutor(CORE_POOL_SIZEMAXIMUM_POOL_SIZE,KEEP_ALIVETimeUnit.SECONDSsPoolWorkQueuesThreadFactory);

深入研究了下源碼,目前默認確實是單一後臺線程執行的,源碼如下:

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();//防備提交的其中某個runnale方法造成異常阻塞其他提交
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
            protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

從上面可以看出,雖然裏面用了線程池,但使用加鎖的機制,並且使用雙向隊列保證了串行提交(不一定是串行執行的,因爲線程池會在提交之後立刻返回,但是如果線程池滿,就要阻塞,這個機制的)。


關於Intent Service
IntentService是一個非常方便的包裝類,具體實現細節詳見官方。
http://developer.android.com/reference/android/app/IntentService.html
其他組件如果需要intentservice完成一個任務,需要啓動Service,並傳遞一個包含完成任務所需參數的intent給它。
IntentService會將收到的所有請求intent放到隊列中,並在異步後臺線程中逐個去處理他們,當處理完所有收到的Intent之後,IntentService終止自己。
IntentService處理了幾乎所有的複雜操作,比如,創建後臺線程、將請求加入隊列、UI線程同步。

關於Loader
Loader是一個抽象類,詳見http://developer.android.com/guide/components/loaders.html
建議使用CursorLoader和AsyncTaskLoader,當然你也可是自己實現Loader,不過更建議實現AsyncTaskLoader。
CursorLoader是應該更具體的實現,用來實現異步查詢Content Resolver並且返回一個cursor。

手動創建線程並實現和GUI同步

這種情況最複雜,涉及到諸多內容,如Hander、Message、Looper、MessageQueue所有android的消息傳遞機制,建議首先研究明白,具體可參見我的博客。
http://zjianjia.blog.163.com/blog/static/174089475201471510424366/

自己寫了一個demo測試了下,源碼放在我的github上,詳見源碼分析,歡迎指正。

https://github.com/yoson/androidThread


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章