【Android】Android 線程&進程模型

1、Java線程

在介紹Android的線程、進程模型之前,首先看一下Java線程相關的內容。

1)線程與進程

線程和進程是對操作系統中程序執行、資源分配的一種抽象,進程有獨立的地址空間,線程附屬於進程並共享進程中的資源。

2)併發與並行

併發:Concurrent,表面上多個程序在同時執行,實際上就是多個程序在分享不同的CPU時間片。
並行:Parallel,真正意義上的同時執行,如在多核處理器的系統中。

3)線程同步

多線程常見的一個問題是線程同步,Java中常用synchronized關鍵字實現同步,synchronized可用於代碼塊、非靜態方法、靜態方法和類。修飾一個代碼塊,被修飾的代碼塊稱爲同步語句塊,其作用的範圍是大括號括起來的代碼,作用的對象是調用這個代碼塊的對象;修飾一個方法,被修飾的方法稱爲同步方法,其作用的範圍是整個方法,作用的對象是調用這個方法的對象;修飾一個靜態的方法,其作用的範圍是整個靜態方法,作用的對象是這個類的所有對象;修飾一個類,其作用的範圍是synchronized後面括號括起來的部分,作用主的對象是這個類的所有對象。
與synchronized關聯的還有兩個同步工具wait和notify,它們是Java對象固有的,本質上是一個monitor,在併發編程時會生效。wait和notify必須在synchronized塊中使用,且作用於同一個monitor。
volatile關鍵字,爲域變量的訪問提供了一種免鎖機制,使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新,因此每次使用該域就要重新計算,而不是使用寄存器中的值,volatile不會提供任何原子操作,它也不能用來修飾final類型的變量。
另外,Java還提供了一些用於線程同步的類,如java.lang.ThreadLocal,java.util.concurrent中的鎖、原子操作、併發數據結構等。
(多進程常見的一個問題是進程間通信,常見的機制有管道pipe、命名管道fifo、信號signal、消息隊列message queue、共享內存shared memory、存儲映射mapped memory、信號量semaphore、套接字socket等,這裏不作詳細介紹。 )

4)線程狀態

java.language.Thread.State定義了下面列出的六個線程狀態,同一時刻只能處於某一狀態。
NEW:至今尚未啓動的線程的狀態。
RUNNABLE:可運行線程的線程狀態。處於可運行狀態的某一線程正在 Java 虛擬機中運行,但它可能正在等待操作系統中的其他資源,比如處理器。
BLOCKED:受阻塞並且正在等待監視器鎖的某一線程的線程狀態。處於受阻塞狀態的某一線程正在等待監視器鎖,以便進入一個同步的塊/方法,或者在調用 Object.wait 之後再次進入同步的塊/方法。
WAITING:某一等待線程的線程狀態。某一線程因爲調用下列方法之一而處於等待狀態:不帶超時值的 Object.wait;不帶超時值的 Thread.join;LockSupport.park。處於等待狀態的線程正等待另一個線程,以執行特定操作。 例如,已經在某一對象上調用了 Object.wait() 的線程正等待另一個線程,以便在該對象上調用 Object.notify() 或 Object.notifyAll()。已經調用了 Thread.join() 的線程正在等待指定線程終止。
TIMED_WAITING:具有指定等待時間的某一等待線程的線程狀態。某一線程因爲調用以下帶有指定正等待時間的方法之一而處於定時等待狀態:Thread.sleep;帶有超時值的 Object.wait;帶有超時值的 Thread.join;LockSupport.parkNanos;LockSupport.parkUntil。
TERMINATED:已終止線程的線程狀態。線程已經結束執行。

5)Thread

使用Thread創建線程,一般有兩種方法,一種是在繼承自Thread的子類中Override run方法,另一種是實現Runnable,如下代碼所示。

        new Thread() {
            @Override
            public void run() {
                Log.d("ThreadTest", "Thread run");
            }
        }.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("ThreadTest", "Runnable run");

            }
        }).start();

另外,還可以使用Future與Runnable結合的FutureTask,實現Callable來創建線程,好處是call方法有返回值,可以拋出異常,代碼如下所示。

        new Thread(new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Log.d("ThreadTest", "Callable call");
                return null;
            }
        }) {
        }).start();

2、runOnUiThread

Activity中的runOnUiThread可以進行轉線程,在Worker Thread調用,傳入一個Runnable,這個Runnalbe就會在UI Thread執行,代碼如下所示。

        new Thread() {
            @Override
            public void run() {
                Log.d("ThreadTest", "run on worker thread");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("ThreadTest", "run on ui thread");
                    }
                });
            }
        }.start();

3、AsyncTask

android.os.AsyncTask用於執行異步任務,內部實現使用了上面提到的Thread、同步方法,以及Android中的Handler。AyncTask泛型包括三個參數,分別爲Params、Progress、Result,以及四個回調,onPreExecute、doInBackground、onProgressUpdate、onPostExecute,其中doInBackground在工作線程執行,其它三個在主線程執行,publishProgress用於更新Progress,之後會調到onProgressUpdate,例子代碼如下。

    new AsyncTask<Integer, Integer, Integer>() {
            @Override
            protected void onPreExecute() {
                Log.d("ThreadTest", "AsyncTask onPreExecute");
            }

            @Override
            protected Integer doInBackground(Integer... params) {
                Log.d("ThreadTest", "AsyncTask doInBackground " + params);
                publishProgress(50);
                publishProgress(100);
                return 100;
            }

            @Override
            protected void onProgressUpdate(Integer... progress) {
                Log.d("ThreadTest", "AsyncTask onProgressUpdate " + progress);
            }

            @Override
            protected void onPostExecute(Integer result) {
                Log.d("ThreadTest", "AsyncTask onPostExecute " + result);
            }
        }.execute(new Integer(1), new Integer(2));

4、Handler

Handler是Android中處理多線程的一種常用機制,涉及的相關類包括Looper、MessageQueue、Message、Runnable。Handler用法主要有兩種,一種是Send Message,另一種是Post Runnable,兩者本質上是一樣的,最終都調用了sendMessageAtTime,將Message放到MessageQueue。示例代碼如下所示。

        new Thread() {
            @Override
            public void run() {
                Log.d("ThreadTest", "Thread run to send message");
                myHandler.sendEmptyMessage(100);
            }
        }.start();

    private MyHandler myHandler = new MyHandler();

    private static class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Log.d("ThreadTest", "Handler handleMessage " + msg);
        }
    }

5、進程

Android基於Linux Kernel,進程管理類似於Linux的管理方式,如常見的權限管理、OOM機制、進程優先級等。
Android中的App是沙箱隔離的,默認運行在獨立的進程中,不過可以通過配置Manifest中的sharedUserId和簽名,以運行在同一進程,運行在同一進程的好處就是數據共享。Android中的Activity、Service默認運行在App進程,可以通過配置Manifest中的android:process屬性讓它們運行在獨立於App的進程中。

6、Binder

Binder是Android中非常重要的一個模塊,用於數據通信。Binder與Linux既有的IPC機制相比,好處是數據拷貝一次,安全性高,使用了面向對象的思想。
Binder實現包括四個部分,分別是Server、Client、ServiceManager和Driver。Driver運行在內核空間,其它三個運行在用戶空間。
Driver是一種廣義上的驅動,與硬件並沒有關係,只是實現方式類似,如常見的open、mmap、poll、ioctl等文件操作。Binder保證IPC只發生一次數據拷貝,從一個進程拷貝到另一個進程,而普通的IPC一般會發生兩次數據拷貝,從用戶空間拷貝到內核空間,再從內核控件拷貝到用戶空間,甚至會拷貝更多次。
ServiceManager類似於網絡中的DNS,將字符形式的Binder名轉換爲Binder實體引用,方便Client通過Binder名獲取Binder實體引用。註冊了名字的Binder爲具名Binder,沒有註冊名字的Binder爲匿名Binder。Server創建Binder實體,然後通過Driver將其傳給ServiceManager,ServiceManager便註冊這個Binder到一個索引表。

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