android什麼是線程
『壹』 android進程和線程到底有什麼區別
進程:是一個具有獨立功能的程序關於某個數據集合的一次運行活動。進程是系統進行資源分配和調度的一個獨立單位。可以申請和擁有系統資源,是一個動態的概念,是一個活動的實體,是一個「執行中的程序」。不只是程序的代碼,還包括當前的活動。
線程:線程是進程的一個實體,是CPU調度和分
派的基本單位,它是比進程更小的能獨立運行的基本單位。線程比進程更小,基本上不擁有系統資源,故對它的調度所用資源小,能更高效的提高系統內多個程序間並發執行的
程度。線程和進程的區別:
1、子進程和父進程有不同的代碼和數據空間,而多個線程則共享數據空間,每個線程有自己的執行堆棧和程序計數器為其執行上下文。
2、進程間相互獨立,同一進程的各線程間共享。某進程內的線程在其它進程不可見。
3、進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變數)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。
4、線程上下文切換比進程上下文切換要快得多。
『貳』 每個Android 都應必須了解的多線程知識點~
進程是系統調度和資源分配的一個獨立單位。
在Android中,一個應用程序就是一個獨立的集成,應用運行在一個獨立的環境中,可以避免其他應用程序/進程的干擾。當我們啟動一個應用程序時,系統就會創建一個進程(該進程是從Zygote中fork出來的,有獨立的ID),接著為這個進程創建一個主線程,然後就可以運行MainActivity了,應用程序的組件默認都是運行在其進程中。開發者可以通過設置應用的組件的運行進程,在清單文件中給組件設置:android:process = "進程名";可以達到讓組件運行在不同進程中的目的。讓組件運行在不同的進程中,既有好處,也有壞處。我們依次的說明下。
好處:每一個應用程序(也就是每一個進程)都會有一個內存預算,所有運行在這個進程中的程序使用的總內存不能超過這個值,讓組件運行不同的進程中,可以讓主進程可以擁有更多的空間資源。當我們的應用程序比較大,需要的內存資源比較多時(也就是用戶會抱怨應用經常出現OutOfMemory時),可以考慮使用多進程。
壞處:每個進程都會有自己的虛擬機實例,因此讓在進程間共享一些數據變得相對困難,需要採用進程間的通信來實現數據的共享。
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。
在Android中,線程會有那麼幾種狀態:創建、就緒、運行、阻塞、結束。當應用程序有組件在運行時,UI線程是處於運行狀態的。默認情況下,應用的所有組件的操作都是在UI線程里完成的,包括響應用戶的操作(觸摸,點擊等),組件生命周期方法的調用,UI的更新等。因此如果UI線程處理阻塞狀態時(在線程里做一些耗時的操作,如網路連接等),就會不能響應各種操作,如果阻塞時間達到5秒,就會讓程序處於ANR(application not response)狀態。
1.線程作用
減少程序在並發執行時所付出的時空開銷,提高操作系統的並發性能。
2.線程分類
守護線程、非守護線程(用戶線程)
2.1 守護線程
定義:守護用戶線程的線程,即在程序運行時為其他線程提供一種通用服務
常見:如垃圾回收線程
設置方式:thread.setDaemon(true);//設置該線程為守護線程
2.2 非守護線程(用戶線程)
主線程 & 子線程。
2.2.1 主線程(UI線程)
定義:Android系統在程序啟動時會自動啟動一條主線程
作用:處理四大組件與用戶進行交互的事情(如UI、界面交互相關)
因為用戶隨時會與界面發生交互,因此主線程任何時候都必須保持很高的響應速度,所以主線程不允許進行耗時操作,否則會出現ANR。
2.2.2 子線程(工作線程)
定義:手動創建的線程
作用:耗時的操作(網路請求、I/O操作等)
2.3 守護線程與非守護線程的區別和聯系
區別:虛擬機是否已退出,即
a. 當所有用戶線程結束時,因為沒有守護的必要,所以守護線程也會終止,虛擬機也同樣退出
b. 反過來,只要任何用戶線程還在運行,守護線程就不會終止,虛擬機就不會退出
3.線程優先順序
3.1 表示
線程優先順序分為10個級別,分別用Thread類常量表示。
3.2 設置
通過方法setPriority(int grade)進行優先順序設置,默認線程優先順序是5,即 Thread.NORM_PRIORITY。
4.線程狀態
創建狀態:當用 new 操作符創建一個線程的時候
就緒狀態:調用 start 方法,處於就緒狀態的線程並不一定馬上就會執行 run 方法,還需要等待CPU的調度
運行狀態:CPU 開始調度線程,並開始執行 run 方法
阻塞(掛起)狀態:線程的執行過程中由於一些原因進入阻塞狀態,比如:調用 sleep/wait 方法、嘗試去得到一個鎖等
結束(消亡)狀態:run 方法執行完 或者 執行過程中遇到了一個異常
(1)start()和run()的區別
通過調用Thread類的start()方法來啟動一個線程,這時此線程是處於就緒狀態,並沒有運行。調用Thread類調用run()方法來完成其運行操作的,方法run()稱為線程體,它包含了要執行的這個線程的內容,run()運行結束,此線程終止,然後CPU再調度其它線程。
(2)sleep()、wait()、yield()的區別
sleep()方法屬於Thread類,wait()方法屬於Object類。
調用sleep()方法,線程不會釋放對象鎖,只是暫停執行指定的時間,會自動恢復運行狀態;調用wait()方法,線程會放棄對象鎖,進入等待此對象的等待鎖定池,不調用notify()方法,線程永遠處於就緒(掛起)狀態。
yield()直接由運行狀態跳回就緒狀態,表示退讓線程,讓出CPU,讓CPU調度器重新調度。禮讓可能成功,也可能不成功,也就是說,回到調度器和其他線程進行公平競爭。
1.Android線程的原則
(1)為什麼不能再主線程中做耗時操作
防止ANR, 不能在UI主線程中做耗時的操作,因此我們可以把耗時的操作放在另一個工作線程中去做。操作完成後,再通知UI主線程做出相應的響應。這就需要掌握線程間通信的方式了。 在Android中提供了兩種線程間的通信方式:一種是AsyncTask機制,另一種是Handler機制。
(2)為什麼不能在非UI線程中更新UI 因為Android的UI線程是非線程安全的,應用更新UI,是調用invalidate()方法來實現界面的重繪,而invalidate()方法是非線程安全的,也就是說當我們在非UI線程來更新UI時,可能會有其他的線程或UI線程也在更新UI,這就會導致界面更新的不同步。因此我們不能在非UI主線程中做更新UI的操作。
2.Android實現多線程的幾種方式
3.為何需要多線程
多線程的本質就是非同步處理,直觀一點說就是不要讓用戶感覺到「很卡」。
4.多線程機制的核心是啥
多線程核心機制是Handler
推薦Handler講解視頻: 面試總被問到Handler?帶你從源碼的角度解讀Handler核心機制
根據上方提到的 多進程、多線程、Handler 問題,我整理了一套 Binder與Handler 機制解析的學習文檔,提供給大家進行學習參考,有需要的可以 點擊這里直接獲取!!! 裡面記錄許多Android 相關學習知識點。
『叄』 Android主線程到底是什麼
Android中關於主線程的理解:
Android的主線程是UI線程,在Android中,四大組件運行在主線程中,在主線程中做耗時操作會導致程序出現卡頓甚至出現ANR異常,一個基本常識就是將耗時操作放到子線程中去處理,然後通過Handler回調到主線程。
有三點還需要注意:
因為四大組件運行在一個主線程中,那麼若果當前界面在顯示的時候,後台的activity仍有處理邏輯再運行的話,仍然會造成當前界面的卡頓。
通過Handler回調到主線程只是避免程序出現ANR的第一步,必須要注意handler中邏輯處理的耗時,如果將很多消息都扔給了handler,那麼也會給主線程造成壓力,導致程序運行卡頓。
四大組件、Handler都是在一個線程中,那麼主線程在同一時刻不可能發送兩個廣播,換句話說就是若果能夠保證所有的廣播都是在主線程中發送,那麼廣播內部其實不需要加上對非同步操作的處理。
『肆』 Android進程與線程區別
所以下來特地去查了以下資料,先說說線程:
(1)在Android APP中,只允許有一個主線程,進行UI的渲染等等,但是不能進行耗時操作(網路交互等等),否則會造成ANR,就是線程阻塞卡死,未響應。
(2)除了主線程之外,耗時操作都應該規范到子線程中,線程之間會有相應的通信方式,但相互獨立。
(3)然後看了一下所查資料:
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程比進程更小,基本上不擁有系統資源,故對它的調度所用資源小,能更高效的提高系統內多個程序間並發執行的。 嗯,從大的說就是這樣。
在平時的Android開發過程中,基本上都會用到線程handler,thread等等,具體的實現方法我就不在這里寫了。
進程:
根據所查資料:是一個具有獨立功能的程序關於某個數據集合的一次運行活動。進程是系統進行資源分配和調度的一個獨立單位。可以申請和擁有系統資源,是一個動態的概念,是一個活動的實體,是一個「執行中的程序」。不只是程序的代碼,還包括當前的活動。
這應該是一個比較大的概念,存在於一個系統中,與線程的區別是:
1、子進程和父進程有不同的代碼和數據空間,而多個線程則共享數據空間,每個線程有自己的執行堆棧和程序計數器為其執行上下文。
2、進程間相互獨立,同一進程的各線程間共享。某進程內的線程在其它進程不可見。
3、進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變數)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。
4、線程上下文切換比進程上下文切換要快得多。
『伍』 android中線程,進程都是什麼意思(通俗易懂的)
android中的進程就是一個個獨立的APP應用。線程可以理解為進程中的時間片斷:從代碼執行的角度來看,主線程就是APP從開始一句一句代碼從上往下執行,而子線程的執行時間片斷與主線程的執行時間片斷是分開的,執行時間不會影響到主線程的執行時間。
『陸』 Android 中的「子線程」解析
Android 中線程可分為 主線程 和 子線程 兩類,其中主線程也就是 UI線程 ,它的主要這作用就是運行四大組件、處理界面交互。子線程則主要是處理耗時任務,也是我們要重點分析的。
首先 java 中的各種線程在 Android 里是通用的,Android 特有的線程形態也是基於 Java 的實現的,所以有必要先簡單的了解下 Java 中的線程,本文主要包括以下內容:
在 Java 中要創建子線程可以直接繼承 Thread 類,重寫 run() 方法:
或者實現 Runnable 介面,然後用Thread執行Runnable,這種方式比較常用:
簡單的總結下:
Callable 和 Runnable 類似,都可以用來處理具體的耗時任務邏輯的,但是但具體的差別在哪裡呢?看一個小例子:
定義 MyCallable 實現了 Callable 介面,和之前 Runnable 的 run() 方法對比下, call() 方法是有返回值的哦,泛型就是返回值的類型:
一般會通過線程池來執行 Callable (線程池相關內容後邊會講到),執行結果就是一個 Future 對象:
可以看到,通過線程池執行 MyCallable 對象返回了一個 Future 對象,取出執行結果。
Future 是一個介面,從其內部的方法可以看出它提供了取消任務(有坑!!!)、判斷任務是否完成、獲取任務結果的功能:
Future 介面有一個 FutureTask 實現類,同時 FutureTask 也實現了 Runnable 介面,並提供了兩個構造函數:
用 FutureTask 一個參數的構造函數來改造下上邊的例子:
FutureTask 內部有一個 done() 方法,代表 Callable 中的任務已經結束,可以用來獲取執行結果:
所以 Future + Callable 的組合可以更方便的獲取子線程任務的執行結果,更好的控制任務的執行,主要的用法先說這么多了,其實 AsyncTask 內部也是類似的實現!
注意, Future 並不能取消掉運行中的任務,這點在後邊的 AsyncTask 解析中有提到。
Java 中線程池的具體的實現類是 ThreadPoolExecutor ,繼承了 Executor 介面,這些線程池在 Android 中也是通用的。使用線程池的好處:
常用的構造函數如下:
一個常規線程池可以按照如下方式來實現:
執行任務:
基於 ThreadPoolExecutor ,系統擴展了幾類具有新特性的線程池:
線程池可以通過 execute() 、 submit() 方法開始執行任務,主要差別從方法的聲明就可以看出,由於 submit() 有返回值,可以方便得到任務的執行結果:
要關閉線程池可以使用如下方法:
IntentService 是 Android 中一種特殊的 Service,可用於執行後台耗時任務,任務結束時會自動停止,由於屬於系統的四大組件之一,相比一般線程具有較高的優先順序,不容易被殺死。用法和普通 Service 基本一致,只需要在 onHandleIntent() 中處理耗時任務即可:
至於 HandlerThread,它是 IntentService 內部實現的重要部分,細節內容會在 IntentService 源碼中說到。
IntentService 首次創建被啟動的時候其生命周期方法 onCreate() 會先被調用,所以我們從這個方法開始分析:
這里出現了 HandlerThread 和 ServiceHandler 兩個類,先搞明白它們的作用,以便後續的分析。
首先看 HandlerThread 的核心實現:
首先它繼承了 Thread 類,可以當做子線程來使用,並在 run() 方法中創建了一個消息循環系統、開啟消息循環。
ServiceHandler 是 IntentService 的內部類,繼承了 Handler,具體內容後續分析:
現在回過頭來看 onCreate() 方法主要是一些初始化的操作, 首先創建了一個 thread 對象,並啟動線程,然後用其內部的 Looper 對象 創建一個 mServiceHandler 對象,將子線程的 Looper 和 ServiceHandler 建立了綁定關系,這樣就可以使用 mServiceHandler 將消息發送到子線程去處理了。
生命周期方法 onStartCommand() 方法會在 IntentService 每次被啟動時調用,一般會這里處理啟動 IntentService 傳遞 Intent 解析攜帶的數據:
又調用了 start() 方法:
就是用 mServiceHandler 發送了一條包含 startId 和 intent 的消息,消息的發送還是在主線程進行的,接下來消息的接收、處理就是在子線程進行的:
當接收到消息時,通過 onHandleIntent() 方法在子線程處理 intent 對象, onHandleIntent() 方法執行結束後,通過 stopSelf(msg.arg1) 等待所有消息處理完畢後終止服務。
為什麼消息的處理是在子線程呢?這里涉及到 Handler 的內部消息機制,簡單的說,因為 ServiceHandler 使用的 Looper 對象就是在 HandlerThread 這個子線程類里創建的,並通過 Looper.loop() 開啟消息循環,不斷從消息隊列(單鏈表)中取出消息,並執行,截取 loop() 的部分源碼:
dispatchMessage() 方法間接會調用 handleMessage() 方法,所以最終 onHandleIntent() 就在子線程中劃線執行了,即 HandlerThread 的 run() 方法。
這就是 IntentService 實現的核心,通過 HandlerThread + Hanlder 把啟動 IntentService 的 Intent 從主線程切換到子線程,實現讓 Service 可以處理耗時任務的功能!
AsyncTask 是 Android 中輕量級的非同步任務抽象類,它的內部主要由線程池以及 Handler 實現,在線程池中執行耗時任務並把結果通過 Handler 機制中轉到主線程以實現UI操作。典型的用法如下:
從 Android3.0 開始,AsyncTask 默認是串列執行的:
如果需要並行執行可以這么做:
AsyncTask 的源碼不多,還是比較容易理解的。根據上邊的用法,可以從 execute() 方法開始我們的分析:
看到 @MainThread 註解了嗎?所以 execute() 方法需要在主線程執行哦!
進而又調用了 executeOnExecutor() :
可以看到,當任務正在執行或者已經完成,如果又被執行會拋出異常!回調方法 onPreExecute() 最先被執行了。
傳入的 sDefaultExecutor 參數,是一個自定義的串列線程池對象,所有任務在該線程池中排隊執行:
可以看到 SerialExecutor 線程池僅用於任務的排隊, THREAD_POOL_EXECUTOR 線程池才是用於執行真正的任務,就是我們線程池部分講到的 ThreadPoolExecutor :
再回到 executeOnExecutor() 方法中,那麼 exec.execute(mFuture) 就是觸發線程池開始執行任務的操作了。
那 executeOnExecutor() 方法中的 mWorker 是什麼? mFuture 是什麼?答案在 AsyncTask 的構造函數中:
原來 mWorker 是一個 Callable 對象, mFuture 是一個 FutureTask 對象,繼承了 Runnable 介面。所以 mWorker 的 call() 方法會在 mFuture 的 run() 方法中執行,所以 mWorker 的 call() 方法在線程池得到執行!
同時 doInBackground() 方法就在 call() 中方法,所以我們自定義的耗時任務邏輯得到執行,不就是我們第二部分講的那一套嗎!
doInBackground() 的返回值會傳遞給 postResult() 方法:
就是通過 Handler 將最終的耗時任務結果從子線程發送到主線程,具體的過程是這樣的, getHandler() 得到的就是 AsyncTask 構造函數中初始化的 mHandler , mHander 又是通過 getMainHandler() 賦值的:
可以在看到 sHandler 是一個 InternalHandler 類對象:
所以 getHandler() 就是在得到在主線程創建的 InternalHandler 對象,所以
就可以完成耗時任務結果從子線程到主線程的切換,進而可以進行相關UI操作了。
當消息是 MESSAGE_POST_RESULT 時,代表任務執行完成, finish() 方法被調用:
如果任務沒有被取消的話執行 onPostExecute() ,否則執行 onCancelled() 。
如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被執行,根據之前的用法可以 onProgressUpdate() 的執行需要我們手動調用 publishProgress() 方法,就是通過 Handler 來發送進度數據:
進行中的任務如何取消呢?AsyncTask 提供了一個 cancel(boolean mayInterruptIfRunning) ,參數代表是否中斷正在執行的線程任務,但是呢並不靠譜, cancel() 的方法注釋中有這么一段:
大致意思就是調用 cancel() 方法後, onCancelled(Object) 回調方法會在 doInBackground() 之後被執行而 onPostExecute() 將不會被執行,同時你應該 doInBackground() 回調方法中通過 isCancelled() 來檢查任務是否已取消,進而去終止任務的執行!
所以只能自己動手了:
AsyncTask 整體的實現流程就這些了,源碼是最好的老師,自己跟著源碼走一遍有些問題可能就豁然開朗了!
『柒』 Android進程和線程的區別
Android進程和線程的區別
下面我先介紹下Android進程和線程各是什麼,然後再一一比較區別下
Android進程基本知識:
當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。 同時,Android會為每個應用程序分配一個單獨的LINUX用戶。Android會盡量保留一個正在運行進程,只在內存資源出現不足時,Android會嘗試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時地響應用戶的事件。
我們可以將一些組件運行在其他進程中,並且可以為任意的進程添加線程。組件運行在哪個進程中是在manifest文件里設置的,其中<Activity>,<Service>,<receiver>和<provider>都有一個process屬性來指定該組件運行在哪個進程之中。我們可以設置這個屬性,使得每個組件運行在它們自己的進程中,或是幾個組件共同享用一個進程,或是不共同享用。<application>元素也有一個process屬性,用來指定所有的組件的默認屬性。
Android中的所有組件都在指定的進程中的主線程中實例化的,對組件的系統調用也是由主線程發出的。每個實例不會建立新的線程。對系統調用進行響應的方法——例如負責執行用戶動作的View.onKeyDown()和組件的生命周期函數——都是運行在這個主線程中的。這意味著當系統調用這個組件時,這個組件不能長時間的阻塞主線程。例如進行網路操作時或是更新UI時,如果運行時間較長,就不能直接在主線程中運行,因為這樣會阻塞這個進程中其他的組件,我們可以將這樣的組件分配到新建的線程中或是其他的線程中運行。
Android會根據進程中運行的組件類別以及組件的狀態來判斷該進程的重要性,Android會首先停止那些不重要的進程。按照重要性從高到低一共有五個級別:
1.1前台進程
前台進程是用戶當前正在使用的進程。只有一些前台進程可以在任何時候都存在。他們是最後一個被結束的,當內存低到根本連他們都不能運行的時候。一般來說, 在這種情況下,設備會進行內存調度,中止一些前台進程來保持對用戶交互的響應。
1.2可見進程
可見進程不包含前台的組件但是會在屏幕上顯示一個可見的進程是的重要程度很高,除非前台進程需要獲取它的資源,不然不會被中止。
1.3服務進程
運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網路下載數據)。只要前台進程和可見進程有足夠的內存,系統不會回收他們。
1.4後台進程
運行著一個對用戶不可見的activity(調用過 onStop() 方法).這些進程對用戶體驗沒有直接的影響,可以在服務進程、可見進程、前台進 程需要內存的時候回收。通常,系統中會有很多不可見進程在運行,他們被保存在LRU (least recently used) 列表中,以便內存不足的時候被第一時間回收。如果一個activity正 確的執行了它的生命周期,關閉這個進程對於用戶體驗沒有太大的影響。
1.5空進程
未運行任何程序組件。運行這些進程的唯一原因是作為一個緩存,縮短下次程序需要重新使用的啟動時間。系統經常中止這些進程,這樣可以調節程序緩存和系統緩存的平衡。
單線程模型
線程在代碼是使用標準的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。具體可以看下面的詳細介紹。
當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。
在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。
2.1 子線程更新UI Android的UI是單線程(Single-threaded)的。
為了避免拖住GUI,一些較費時的對象應該交給獨立的線程去執行。如果幕後的線程來執行UI對象,Android就會發出錯誤訊息 。以後遇到這樣的異常拋出時就要知道怎麼回事了!
2.2 Message Queue
在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:
2..3 Message 消息
理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。
2.4. Handler 處理者
是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message) 方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。
2.5. Message Queue 消息隊列
用來存放通過Handler發布的消息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。
2.6 Looper Looper是每條線程里的Message Queue的管家。
Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper()得到當前線程的Looper就有可能為NULL。
從以上幾點,不難看出Android進程和線程的二者的區別所在。
『捌』 安卓開發線程和進程講解
本教程為大家介紹安卓開發中的線程和進程,安卓平台中當首次啟動運行一個組件的時候,Android會相應的啟動了一個進程。默認的,所有的組件和程序運行在這個進程和線程中,也可以安排組件在其他的進程或者線程中運行。
進程:組件運行的進程由manifest file控制。組件的節點activity, service, receiver, 和 provider 都包含一個 process 屬性。這個屬性可以設置組件運行的進程:可以配置組件在一個獨立進程運行,或者多個組件在同一個進程運行。甚至可以多個程序在一個進程中運行——如果這些程序共享一個User ID並給定同樣的許可權。 節點也包含 process 屬性,用來設置程序中所有組件的默認進程。
所有的組件在此進程的主線程中實例化,系統對這些組件的調用從主線程中分離。並非每個對象都會從主線程中分離。一般來說,響應例如View.onKeyDown()用戶操作的方法和通知的方法也在主線程中運行。這就表示,組件被系統調用的時候不應該長時間運行或者阻塞操作(如網路操作或者計算大量數據),因為這樣會阻塞進程中的其他組件。可以把這類操作從主線程中分離。
當更加常用的進程無法獲取足夠內存,Android可能會關閉不常用的進程。下次啟動程序的時候會重新啟動進程。
當決定哪個進程需要被關閉的時候, Android會考慮哪個對用戶更加有用。如Android會傾向於關閉一個長期不顯示在界面的旦頌殲進程來支持一個經常顯示在界面的進程。
線程:即使為組件分配了不同的進程,有時候也需要再分配線程。比如用戶界面需要很快對用戶進行響應,因此某些費時的操作,如網路連接、下載或者非常佔用伺服器時間的操作應該放到其他線程。
線程通過java的標准對象Thread 創建. Android 提供了很多方便的管理線程的方法:— Looper 在線程中運行一個消息循環; Handler 傳遞一個消息; HandlerThread 創建一個帶有消息循環的線程。
遠程調用Remote procere calls
Android有一個遠程調用(RPCs) 的輕量級機制— 通過這個機制,方法可以在本地調用,在遠程執行(在其他進程執行),還可以返回一個值。要實現這個需求,必須分解方法調用,並且所有要傳遞的數據必須是操作系統可以訪問的級別。從本地的進程和內存地址傳送到遠程的進程和內存地櫻正址並在遠程處理和返回。返回值必須向相反的方向傳遞。Android提供了做以上操作的代碼,所以開發者可以專注於實現RPC的介面。
一個RPC介面只能包含方法。所有的方法都是同步執行的(直到遠程方法返回,本地方法才結束阻塞),沒有返回值的時候也是如此。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現的介面, aidl 工具可以生成用於java的介面定義,本地和遠程都要使用這個定義。它包含2個類,
inner類包含了所有的管理遠程程序(符合IDL描述的介面)所需要的代碼。所有的inner類實現了IBinder 介面.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現遠程調用,這個類包含RPC介面。開發者可以繼承Stub類來實現需要的方法。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統這個進程的信息並和其他進程通信),它也會包含aidl 工具產生的介面文件,Stub類實現了遠處那個方法。服務的客戶端只需要aidl 工具產生的介面文件。
以下是如何連接服務和客戶端調用:
·服務的客戶端(本地)會實現onServiceConnected() 和onServiceDisconnected() 方法,這樣,當客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務的連接。
· 服務的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務). 如果服務接收了連接,會返回一個Stub類的實例.
· 如果服務接受了連接,Android會調用客戶端的onServiceConnected() 方法,模沖並傳遞一個Ibinder對象(系統管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務。
以上的描述省略很多RPC的機制。請參見Designing a Remote Interface Using AIDL 和 IBinder 類。
線程安全的方法
在某些情況下,方法可能調用不止一個的線程,因此需要注意方法的線程安全。
對於可以遠程調用的方法,也要注意這點。當一個調用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在Ibinder的進程中執行。但是,如果調用者發起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調用onBind() 方法,onBind() 返回的對象(如實現了RPC的Stub子類)中的方法會被從線程池中調用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調用IBinder的方法。因此IBinder必須線程安全。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現的介面, aidl 工具可以生成用於java的介面定義,本地和遠程都要使用這個定義。它包含2個類,
inner類包含了所有的管理遠程程序(符合IDL描述的介面)所需要的代碼。所有的inner類實現了IBinder 介面.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現遠程調用,這個類包含RPC介面。開發者可以繼承Stub類來實現需要的方法。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統這個進程的信息並和其他進程通信),它也會包含aidl 工具產生的介面文件,Stub類實現了遠處那個方法。服務的客戶端只需要aidl 工具產生的介面文件。
以下是如何連接服務和客戶端調用:
·服務的客戶端(本地)會實現onServiceConnected() 和onServiceDisconnected() 方法,這樣,當客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務的連接。
· 服務的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務). 如果服務接收了連接,會返回一個Stub類的實例.
· 如果服務接受了連接,Android會調用客戶端的onServiceConnected() 方法,並傳遞一個Ibinder對象(系統管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務。
線程安全的方法
在某些情況下,方法可能調用不止一個的線程,因此需要注意方法的線程安全。
對於可以遠程調用的方法,也要注意這點。當一個調用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在Ibinder的進程中執行。但是,如果調用者發起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調用onBind() 方法,onBind() 返回的對象(如實現了RPC的Stub子類)中的方法會被從線程池中調用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調用IBinder的方法。因此IBinder必須線程安全。
簡單來說,一個content provider 可以接收其他進程的數據請求。即使ContentResolver和ContentProvider類沒有隱藏了管理交互的細節,ContentProvider中響應這些請求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的線程池中被調用的,而不是ContentProvider的本身進程。因為這些方法可能是同時從很多線程池運行的,所以這些方法必須要線程安全。
『玖』 Android中的線程和線程池
一、除了Thread外,扮演線程角色的還有:AsyncTask和IntentService,同時HandlerThread也扮演特殊的線程。
IntentService:內部採用HandlerThread來執行,像一個後台線程,同時是一個服務,不容易被系統殺死。
二、HandlerThread的run方法是一個無限循環
三、IntentService中任務是排隊執行的
四、AsyncTask
1、Android1.6之前串悄段桐行執行任務,1.6時候採用線程池裡的並行,Android3.0開始又開始串列(為了避免並發錯誤),單任可以並行。
2、AsyncTask必須在UI線程調用(不過這個不是絕對的,和版本有關燃腔系,API 16之前,API 16到 22, API 22以後) 參考一
原因:內部有靜態Handler,採用UI線程的Looper來處理消息,這就是為什麼AsyncTask必須在UI線程調用,因為子線程默認沒有Looper無法創建下面的Handler,程序會直接Crash
3、AsyncTask中有兩個線程池和一個Handler,一個線程池用啟坦於任務排隊,一個線程池用於真正的執行任務,InternalHandler用於將
執行環境從線程池切換到主線程
AsyncTask串列與並行
五、線程池
線程池中多餘的線程是如何回收的
『拾』 Android線程池的使用
在Android中有主線程和子線程的區分。主線程又稱為UI線程,主要是處理一些和界面相關的事情,而子線程主要是用於處理一些耗時比較大的一些任務,例如一些網路操作,IO請求等。如果在主線程中處理這些耗時的任務,則有可能會出現ANR現象(App直接卡死)。
線程池,從名字的表明含義上我們知道線程池就是包含線程的一個池子,它起到新建線程、管理線程、調度線程等作用。
既然Android中已經有了線程的概念,那麼為什麼需要使用線程池呢?我們從兩個方面給出使用線程池的原因。
在Android中線程池就是ThreadPoolExecutor對象。我們先來看一下ThreadPoolExecutor的構造函數。
我們分別說一下當前的幾個參數的含義:
第一個參數corePoolSize為 核心線程數 ,也就是說線程池中至少有這么多的線程,即使存在的這些線程沒有執行任務。但是有一個例外就是,如果在線程池中設置了allowCoreThreadTimeOut為true,那麼在 超時時間(keepAliveTime) 到達後核心線程也會被銷毀。
第二個參數maximumPoolSize為 線程池中的最大線程數 。當活動線程數達到這個數後,後續添加的新任務會被阻塞。
第三個參數keepAliveTime為 線程的保活時間 ,就是說如果線程池中有多於核心線程數的線程,那麼在線程沒有任務的那一刻起開始計時,如果超過了keepAliveTime,還沒有新的任務過來,則該線程就要被銷毀。同時如果設置了allowCoreThreadTimeOut為true,該時間也就是上面第一條所說的 超時時間 。
第四個參數unit為 第三個參數的計時單位 ,有毫秒、秒等。
第五個參數workQueue為 線程池中的任務隊列 ,該隊列持有由execute方法傳遞過來的Runnable對象(Runnable對象就是一個任務)。這個任務隊列的類型是BlockQueue類型,也就是阻塞隊列,當隊列的任務數為0時,取任務的操作會被阻塞;當隊列的任務數滿了(活動線程達到了最大線程數),添加操作就會阻塞。
第六個參數threadFactory為 線程工廠 ,當線程池需要創建一個新線程時,使用線程工廠來給線程池提供一個線程。
第七個參數handler為 拒絕策略 ,當線程池使用有界隊列時(也就是第五個參數),如果隊列滿了,任務添加到線程池的時候的一個拒絕策略。
可以看到FixedThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出FixedThreadPool的幾個特點:
可以看到CacheThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出CacheThreadPool的幾個特點:
可以看到ScheledThreadPoolExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出ScheledThreadPoolExecutor的幾個特點:
可以看到SingleThreadExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出SingleThreadExecutor的幾個特點: