導航:首頁 > 操作系統 > android線程內存

android線程內存

發布時間:2023-03-26 11:01:38

『壹』 android中的線程與進程之間的關系簡單解釋

一、Android中的進程
當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。 同時,Android會為每個應用程序分配一個單獨的LINUX用戶。Android會盡量保留一個正在運行進程,只在內存資源出現不足時,Android會嘗試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時地響應用戶的事件。
我們可以將一些組件運行在其他進程中,並且可以為任意的進程添加線程。組件運行在哪個進程中是在manifest文件里設置的,其中<Activity>,<Service>,<receiver>和<provider>都有一個process屬性來指定該組件運行在哪個進程之中。我們可以設置這個屬性,使得每個組件運行在它們自己的進程中,或是幾個組件共同享用一個進程,或是不共同享用。<application>元素也有一個process屬性,用來指定所有的組件的默認屬性。
Android中的所有組件都在指定的進程中的主線程中實例化的,對組件的系統調用也是由主線程發出的。每個實例不會建立新的線程。對系統調用進行響應的方法——例如負責執行用戶動作的View.onKeyDown()和組件的生命周期函數——都是運行在這個主線程中的。這意味著當系統調用這個組件時,這個組件不能長時間的阻塞主線程。例如進行網路操作時或是更新UI時,如果運行時間較長,就不能直接在主線程中運行,因為這樣會阻塞這個進程中其他的組件,我們可以將這樣的組件分配到新建的線程中或是其他的線程中運行。
二、Android中的線程
線程在代碼是使用標準的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。
三、進程與線程的關系
它們之間的區別:

1、線程是進程的一部分,所以線程有的時候被稱為是輕權進程或者輕量級進程。
2、一個沒有線程的進程是可以被看作單線程的,如果一個進程內擁有多個進程,進程的執行過程不是一條線(線程)的,而是多條線(線程)共同完成的。
3、系統在運行的時候會為每個進程分配不同的內存區域,但是不會為線程分配內存(線程所使用的資源是它所屬的進程的資源),線程組只能共享資源。那就是說,出了CPU之外(線程在運行的時候要佔用CPU資源),計算機內部的軟硬體資源的分配與線程無關,線程只能共享它所屬進程的資源。
4、與進程的控製表PCB相似,線程也有自己的控製表TCB,但是TCB中所保存的線程狀態比PCB表中少多了。
5、進程是系統所有資源分配時候的一個基本單位,擁有一個完整的虛擬空間地址,並不依賴線程而獨立存在。
它們之間的聯系:
簡單的說就是:一個程序包含進程,進程又包含線程,線程是進程的一個組成部分,進程是操作系統分配資源的基本單位,線程是不會分配資源的,一個進程可以包含多個線程,然後這些線程共享進程的資源。
分開來說就是:
線程是進程的一個實體,是CPU 調度和分配的基本單位,其本身不擁有系統資源,只含有程序計數器、寄存器和棧等一些運行時必不可少的基本資源。同屬一個進程的線程共享進程中的全部資源。
進程是系統資源分配時的一個基本單位,擁有一個完整的虛擬空間地址。
系統在運行的時候會為每個進程分配不同的內存區域。
線程組只能共享資源,即除了CPU外,計算機內部的軟硬體資源的分配與線程無關,線程只能共享它所屬進程的資源。

『貳』 Android線程優先順序和進程oom_adj

在處理app啟動拍脊速度的時候,可以設置主線程的優先順序,保證主線程佔用的cpu足夠久。進程的oom_adj,決定了當內存不夠的時候,lmk會根據oom_adj的大小依次釋放內存。

android中對線程等級劃分如下:

設置線程的優先順序分為:android 提供的api和java sdk自帶的api
注意: 要羨鏈使用android提供的api設置,用java提供的作用不夠顯著

作用: 可以在主線程設置主線層等級;在Glide載入圖片的時候設置低優先順序。當圖片量很大的時候可以降低載入圖片線程的等級

android內存不夠了,會觸發oom機制,lowMemoryKiller會根據每個進程的oom_adj的等級,依次殺死進程,釋放內存。

lom會根據free的內存的值,來判斷kill掉哪個等級下的進程。例如當空閑內存只有64M了。會kill掉oom_adj 為12-15的進程

真實案例:應用A跳到第三方應用B,在第三方應用兄賀孫B中播放視頻,載入大量圖片,導致返回的時候,應用A走了SplashActivity。通過logcat發現A應用被kill掉了

『叄』 Android中線程與線程,進程與進程之間如何通信

使用handler發送message,消息隊列排隊

進程是一個具有獨立功能的程序關於某個數據集合的一次運行活動。它可以申請和擁有系統資源,是一個動態的概念,是一個活動的實體。它不只是程序的代碼,還包括當前的活動,通過程序計數器的值和處理寄存器的內容來表示。
進程是一個「執行中的程序」。程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體,我們稱其為進程。
通常在一個進程中可以包含若干個線程,它們可以利用進程所擁有的資源。在引入線程的操作系統中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。由於線程比進程更小,基本上不擁有系統資源,故對它的調度所付出的開銷就會小得多,能更高效的提高系統內多個程序間並發執行的程度。
線程和進程的區別在於,子進程和父進程有不同的代碼和數據空間,而多個線程則共享數據空間,每個線程有自己的執行堆棧和程序計數器為其執行上下文。多線程主要是為了節約CPU時間,發揮利用,根據具體情況而定。線程的運行中需要使用計算機的內存資源和CPU。

『肆』 安卓如何降低運行內存

降低運行內存:

1、一些軟體可進行手動結束線程(進程)釋放內存。具體視系統和軟體而定。線程分兩種,一種是手機自帶的,一種是後來安裝的。 非手機自帶都可以關閉。

2、手機自帶的程序,如果不清楚作用的話,最好不要隨便關閉,關閉後可能導致手機的部分功能不能使用或手機出錯重新啟動, 因為系統自帶程序即使關閉後下次啟動還會運行,所以一般只在有特殊需要的時候才使用。

3、進入航空模式(飛行模式或者離線模式),這樣就關閉了通訊相關的線程,以獲得更大的運行內存。這也只是在有特殊需要的時候使用,比如需要玩一個運行內存要求非常高的游戲。

(4)android線程內存擴展閱讀:

手機運行內存注意事項

1、大內存可能是手機廠商的一種營銷手段 ,通過參數引誘消費者選擇大內存的手機。

2、不能盲目地相信內存總數 。 根據手機系統定製化的不同,實際可用的運行內存也會有相應的浮動。 比如一款機型是 4GB 內存, 但實際上可用內存空間只有2GB 左右。

3、RAM 內存的大小會在一定程度上影響手機速度,但並不是決定性因素,畢竟手機運行速度是由 CPU、GPU、RAM、ROM、系統優化共同來決定的。

『伍』 Android中的線程狀態 - AsyncTask詳解

在操作系統中,線程是操作系統調度的最小單元,同時線程又是一種受限的系統資源,即線程不可能無限制地產生,並且 線程的創建和銷毀都會有相應的開銷。 當系統中存在大量的線程時,系統會通過會時間片輪轉的方式調度每個線程,因此線程不可能做到絕對的並行。

如果在一個進程中頻繁地創建和銷毀線程,顯然不是高效的做法。正確的做法是採用線程池,一個線程池中會緩存一定數量的線程,通過線程池就可以避免因為頻繁創建和銷毀線程所帶來的系統開銷。

AsyncTask是一個抽象類,它是由Android封裝的一個輕量級非同步類(輕量體現在使用方便、代碼簡潔),它可以在線程池中執行後台任務,然後把執行的進度和最終結果傳遞給主線程並在主線程中更新UI。

AsyncTask的內部封裝了 兩個線程池 (SerialExecutor和THREAD_POOL_EXECUTOR)和 一個Handler (InternalHandler)。

其中 SerialExecutor線程池用於任務的排隊,讓需要執行的多個耗時任務,按順序排列 THREAD_POOL_EXECUTOR線程池才真正地執行任務 InternalHandler用於從工作線程切換到主線程

1.AsyncTask的泛型參數

AsyncTask是一個抽象泛型類。

其中,三個泛型類型參數的含義如下:

Params: 開始非同步任務執行時傳入的參數類型;

Progress: 非同步任務執行過程中,返回下載進度值的類型;

Result: 非同步任務執行完成後,返回的結果類型;

如果AsyncTask確定不需要傳遞具體參數,那麼這三個泛型參數可以用Void來代替。

有了這三個參數類型之後,也就控制了這個AsyncTask子類各個階段的返回類型,如果有不同業務,我們就需要再另寫一個AsyncTask的子類進行處理。

2.AsyncTask的核心方法

onPreExecute()

這個方法會在 後台任務開始執行之間調用,在主線程執行。 用於進行一些界面上的初始化操作,比如顯示一個進度條對話框等。

doInBackground(Params...)

這個方法中的所有代碼都會 在子線程中運行,我們應該在這里去處理所有的耗時任務。

任務一旦完成就可以通過return語句來將任務的執行結果進行返回,如果AsyncTask的第三個泛型參數指定的是Void,就可以不返回任務執行結果。 注意,在這個方法中是不可以進行UI操作的,如果需要更新UI元素,比如說反饋當前任務的執行進度,可以調用publishProgress(Progress...)方法來完成。

onProgressUpdate(Progress...)

當在後台任務中調用了publishProgress(Progress...)方法後,這個方法就很快會被調用,方法中攜帶的參數就是在後台任務中傳遞過來的。 在這個方法中可以對UI進行操作,在主線程中進行,利用參數中的數值就可以對界面元素進行相應的更新。

onPostExecute(Result)

當doInBackground(Params...)執行完畢並通過return語句進行返回時,這個方法就很快會被調用。返回的數據會作為參數傳遞到此方法中, 可以利用返回的數據來進行一些UI操作,在主線程中進行,比如說提醒任務執行的結果,以及關閉掉進度條對話框等。

上面幾個方法的調用順序:

onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()

如果不需要執行更新進度則為onPreExecute() --> doInBackground() --> onPostExecute(),

除了上面四個方法,AsyncTask還提供了onCancelled()方法, 它同樣在主線程中執行,當非同步任務取消時,onCancelled()會被調用,這個時候onPostExecute()則不會被調用 ,但是要注意的是, AsyncTask中的cancel()方法並不是真正去取消任務,只是設置這個任務為取消狀態,我們需要在doInBackground()判斷終止任務。就好比想要終止一個線程,調用interrupt()方法,只是進行標記為中斷,需要在線程內部進行標記判斷然後中斷線程。

3.AsyncTask的簡單使用

這里我們模擬了一個下載任務,在doInBackground()方法中去執行具體的下載邏輯,在onProgressUpdate()方法中顯示當前的下載進度,在onPostExecute()方法中來提示任務的執行結果。如果想要啟動這個任務,只需要簡單地調用以下代碼即可:

4.使用AsyncTask的注意事項

①非同步任務的實例必須在UI線程中創建,即AsyncTask對象必須在UI線程中創建。

②execute(Params... params)方法必須在UI線程中調用。

③不要手動調用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)這幾個方法。

④不能在doInBackground(Params... params)中更改UI組件的信息。

⑤一個任務實例只能執行一次,如果執行第二次將會拋出異常。

先從初始化一個AsyncTask時,調用的構造函數開始分析。

這段代碼雖然看起來有點長,但實際上並沒有任何具體的邏輯會得到執行,只是初始化了兩個變數,mWorker和mFuture,並在初始化mFuture的時候將mWorker作為參數傳入。mWorker是一個Callable對象,mFuture是一個FutureTask對象,這兩個變數會暫時保存在內存中,稍後才會用到它們。 FutureTask實現了Runnable介面,關於這部分內容可以看這篇文章。

mWorker中的call()方法執行了耗時操作,即result = doInBackground(mParams);,然後把執行得到的結果通過postResult(result);,傳遞給內部的Handler跳轉到主線程中。在這里這是實例化了兩個變數,並沒有開啟執行任務。

那麼mFuture對象是怎麼載入到線程池中,進行執行的呢?

接著如果想要啟動某一個任務,就需要調用該任務的execute()方法,因此現在我們來看一看execute()方法的源碼,如下所示:

調用了executeOnExecutor()方法,具體執行邏輯在這個方法裡面:

可以 看出,先執行了onPreExecute()方法,然後具體執行耗時任務是在exec.execute(mFuture),把構造函數中實例化的mFuture傳遞進去了。

exec具體是什麼?

從上面可以看出具體是sDefaultExecutor,再追溯看到是SerialExecutor類,具體源碼如下:

終於追溯到了調用了SerialExecutor 類的execute方法。SerialExecutor 是個靜態內部類,是所有實例化的AsyncTask對象公有的,SerialExecutor 內部維持了一個隊列,通過鎖使得該隊列保證AsyncTask中的任務是串列執行的,即多個任務需要一個個加到該隊列中,然後執行完隊列頭部的再執行下一個,以此類推。

在這個方法中,有兩個主要步驟。

①向隊列中加入一個新的任務,即之前實例化後的mFuture對象。

②調用 scheleNext()方法,調用THREAD_POOL_EXECUTOR執行隊列頭部的任務。

由此可見SerialExecutor 類僅僅為了保持任務執行是串列的,實際執行交給了THREAD_POOL_EXECUTOR。

THREAD_POOL_EXECUTOR又是什麼?

實際是個線程池,開啟了一定數量的核心線程和工作線程。然後調用線程池的execute()方法。執行具體的耗時任務,即開頭構造函數中mWorker中call()方法的內容。先執行完doInBackground()方法,又執行postResult()方法,下面看該方法的具體內容:

該方法向Handler對象發送了一個消息,下面具體看AsyncTask中實例化的Hanlder對象的源碼:

在InternalHandler 中,如果收到的消息是MESSAGE_POST_RESULT,即執行完了doInBackground()方法並傳遞結果,那麼就調用finish()方法。

如果任務已經取消了,回調onCancelled()方法,否則回調 onPostExecute()方法。

如果收到的消息是MESSAGE_POST_PROGRESS,回調onProgressUpdate()方法,更新進度。

InternalHandler是一個靜態類,為了能夠將執行環境切換到主線程,因此這個類必須在主線程中進行載入。所以變相要求AsyncTask的類必須在主線程中進行載入。

到此為止,從任務執行的開始到結束都從源碼分析完了。

AsyncTask的串列和並行

從上述源碼分析中分析得到,默認情況下AsyncTask的執行效果是串列的,因為有了SerialExecutor類來維持保證隊列的串列。如果想使用並行執行任務,那麼可以直接跳過SerialExecutor類,使用executeOnExecutor()來執行任務。

四、AsyncTask使用不當的後果

1.)生命周期

AsyncTask不與任何組件綁定生命周期,所以在Activity/或者Fragment中創建執行AsyncTask時,最好在Activity/Fragment的onDestory()調用 cancel(boolean);

2.)內存泄漏

3.) 結果丟失

屏幕旋轉或Activity在後台被系統殺掉等情況會導致Activity的重新創建,之前運行的AsyncTask(非靜態的內部類)會持有一個之前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將不再生效。

自己是從事了七年開發的Android工程師,不少人私下問我,2019年Android進階該怎麼學,方法有沒有?

沒錯,年初我花了一個多月的時間整理出來的學習資料,希望能幫助那些想進階提升Android開發,卻又不知道怎麼進階學習的朋友。【 包括高級UI、性能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的復習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。

『陸』 Android線程池ThreadPoolExecutor詳解

       傳統的多線程是通過繼承Thread類及實現Runnable介面來實現的,每次創建及銷毀線程都會消耗資源、響應速度慢,且線程缺乏統一管理,容易出現阻塞的情況,針對以上缺點,線程池就出現了。

       線程池是一個創建使用線程並能保存使用過的線程以達到復用的對象,簡單的說就是一塊緩存了一定數量線程的區域。

       1.復用線程:線程執行完不會立刻退出,繼續執行其他線程;
       2.管理線程:統一分配、管理、控制最大並發數;

       1.降低因頻繁創建&銷毀線程帶來的性能開銷,復用緩存在線程池中的線程;
       2.提高線程執行效率&響應速度,復用線程:響應速度;管理線程:優化線程執行順序,避免大量線程搶占資源導致阻塞現象;
       3.提高對線程的管理度;

       線程池的使用也比較簡單,流程如下:

       接下來通過源碼來介紹一下ThreadPoolExecutor內部實現及工作原理。

       線程池的最終實現類是ThreadPoolExecutor,通過實現可以一步一步的看到,父介面為Executor:

       其他的繼承及實現關系就不一一列舉了,直接通過以下圖來看一下:

       從構造方法開始看:

       通過以上可以看到,在創建ThreadPoolExecutor時,對傳入的參數是有要求的:corePoolSize不能小於0;maximumPoolSize需要大於0,且需要大於等於corePoolSize;keepAliveTime大於0;workQueue、threadFactory都不能為null。
       在創建完後就需要執行Runnable了,看以下execute()方法:

       在execute()內部主要執行的邏輯如下:
       分析點1:如果當前線程數未超過核心線程數,則將runnable作為參數執行addWorker(),true表示核心線程,false表示非核心線程;
       分析點2:核心線程滿了,如果線程池處於運行狀態則往workQueue隊列中添加任務,接下來判斷是否需要拒絕或者執行addWorker();
       分析點3:以上都不滿足時 [corePoolSize=0且沒有運行的線程,或workQueue已經滿了] ,執行addWorker()添加runnable,失敗則執行拒絕策略;
        總結一下:線程池對線程創建的管理,流程圖如下:

       在執行addWorker時,主要做了以下兩件事:
       分析點1:將runnable作為參數創建Worker對象w,然後獲取w內部的變數thread;
       分析點2:調用start()來啟動thread;
       在addWorker()內部會將runnable作為參數傳給Worker,然後從Worker內部讀取變數thread,看一下Worker類的實現:

       Worker實現了Runnable介面,在Worker內部,進行了賦值及創建操作,先將execute()時傳入的runnable賦值給內部變數firstTask,然後通過ThreadFactory.newThread(this)創建Thread,上面講到在addWorker內部執行t.start()後,會執行到Worker內部的run()方法,接著會執行runWorker(this),一起看一下:

       前面可以看到,runWorker是執行在子線程內部,主要執行了三件事:
       分析1:獲取當前線程,當執行shutdown()時需要將線程interrupt(),接下來從Worker內部取到firstTask,即execute傳入的runnable,接下來會執行;
       分析2:while循環,task不空直接執行;否則執行getTask()去獲取,不為空直接執行;
       分析3:對有效的task執行run(),由於是在子線程中執行,因此直接run()即可,不需要start();
       前面看到,在while內部有執行getTask(),一起看一下:

       getTask()是從workQueue內部獲取接下來需要執行的runnable,內部主要做了兩件事:
       分析1:先獲取到當前正在執行工作的線程數量wc,通過判斷allowCoreThreadTimeOut[在創建ThreadPoolExecutor時可以進行設置]及wc > corePoolSize來確定timed值;
       分析2:通過timed值來決定執行poll()或者take(),如果WorkQueue中有未執行的線程時,兩者作用是相同的,立刻返回線程;如果WorkQueue中沒有線程時,poll()有超時返回,take()會一直阻塞;如果allowCoreThreadTimeOut為true,則核心線程在超時時間沒有使用的話,是需要退出的;wc > corePoolSize時,非核心線程在超時時間沒有使用的話,是需要退出的;
       allowCoreThreadTimeOut是可以通過以下方式進行設置的:

       如果沒有進行設置,那麼corePoolSize數量的核心線程會一直存在。
        總結一下:ThreadPoolExecutor內部的核心線程如何確保一直存在,不退出?
       上面分析已經回答了這個問題,每個線程在執行時會執行runWorker(),而在runWorker()內部有while()循環會判斷getTask(),在getTask()內部會對當前執行的線程數量及allowCoreThreadTimeOut進行實時判斷,如果工作數量大於corePoolSize且workQueue中沒有未執行的線程時,會執行poll()超時退出;如果工作數量不大於corePoolSize且workQueue中沒有未執行的線程時,會執行take()進行阻塞,確保有corePoolSize數量的線程阻塞在runWorker()內部的while()循環不退出。
       如果需要關閉線程池,需要如何操作呢,看一下shutdown()方法:

       以上可以看到,關閉線程池的原理:a. 遍歷線程池中的所有工作線程;b. 逐個調用線程的interrupt()中斷線程(註:無法響應中斷的任務可能永遠無法終止)
       也可調用shutdownNow()來關閉線程池,二者區別:
       shutdown():設置線程池的狀態為SHUTDOWN,然後中斷所有沒有正在執行任務的線程;
       shutdownNow():設置線程池的狀態為STOP,然後嘗試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表;
       使用建議:一般調用shutdown()關閉線程池;若任務不一定要執行完,則調用shutdownNow();
        總結一下:ThreadPoolExecutor在執行execute()及shutdown()時的調用關系,流程圖如下:

       線程池可以通過Executors來進行不同類型的創建,具體分為四種不同的類型,如下:

       可緩存線程池:不固定線程數量,且支持最大為Integer.MAX_VALUE的線程數量:

       1、線程數無限制
       2、有空閑線程則復用空閑線程,若無空閑線程則新建線程
       3、一定程度上減少頻繁創建/銷毀線程,減少系統開銷

       固定線程數量的線程池:定長線程池

       1、可控制線程最大並發數(同時執行的線程數)
       2、超出的線程會在隊列中等待。

       單線程化的線程池:可以理解為線程數量為1的FixedThreadPool

       1、有且僅有一個工作線程執行任務
       2、所有任務按照指定順序執行,即遵循隊列的入隊出隊規則

       定時以指定周期循環執行任務

       一般來說,等待隊列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 與 SynchronousQueue 。
       假設向線程池提交任務時,核心線程都被佔用的情況下:
        ArrayBlockingQueue :基於數組的阻塞隊列,初始化需要指定固定大小。
       當使用此隊列時,向線程池提交任務,會首先加入到等待隊列中,當等待隊列滿了之後,再次提交任務,嘗試加入隊列就會失敗,這時就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。所以最終可能出現後提交的任務先執行,而先提交的任務一直在等待。
        LinkedBlockingQueue :基於鏈表實現的阻塞隊列,初始化可以指定大小,也可以不指定。
       當指定大小後,行為就和 ArrayBlockingQueue一致。而如果未指定大小,則會使用默認的 Integer.MAX_VALUE 作為隊列大小。這時候就會出現線程池的最大線程數參數無用,因為無論如何,向線程池提交任務加入等待隊列都會成功。最終意味著所有任務都是在核心線程執行。如果核心線程一直被占,那就一直等待。
        SynchronousQueue :無容量的隊列。
       使用此隊列意味著希望獲得最大並發量。因為無論如何,向線程池提交任務,往隊列提交任務都會失敗。而失敗後如果沒有空閑的非核心線程,就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。完全沒有任何等待,唯一制約它的就是最大線程數的個數。因此一般配合Integer.MAX_VALUE就實現了真正的無等待。
       但是需要注意的是, 進程的內存是存在限制的,而每一個線程都需要分配一定的內存。所以線程並不能無限個。

『柒』 android 啟動一個線程後 怎麼關閉 並釋放內存

1、線程裡面的代碼運行完,就Game Over了。
2、如果線程中的代碼是個死循環。可使用標識來確定是否然代碼運行完
在子線程中運行代碼如下
boolean flag = true;
while(flag){
//正常運行的代碼
...
...
//更改flag標識的更改情況,false:跳出循環,線程運行完畢結束,true繼續循環
....
}

『捌』 android線程超過多少會oom

首先要說一點,就是在Android中線程數超過一定量,也會拋出OOM,所以OOM不一定是內存不足了才會拋出OOM。
具體數量的問題,每個廠商、每個具體型號的手機最大數量都不太一樣,華為有些手機限制400多個,默認的話應該是1000多個。

『玖』 Android進程間和線程間通信方式

        進程:是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。

  線程:是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。

  區別:

  (1)、一個程序至少有一個進程,一個進程至少有一個線程;

  (2)、線程的劃分尺度小於進程,使得多線程程序的並發性高;

  (3)、進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉。

---------------------

一、Android進程間通信方式

1.Bundle

  由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。

  缺點:無法傳輸Bundle不支持的數據類型。

2.ContentProvider

  ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content Provider可以跨進程訪問其他應用程序中的數據。用法是繼承ContentProvider,實現onCreate,query,update,insert,delete和getType方法,onCreate是負責創建時做一些初始化的工作,增刪查改的方法就是對數據的查詢和修改,getType是返回一個String,表示Uri請求的類型。注冊完後就可以使用ContentResolver去請求指定的Uri。

3.文件

  兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當並發讀/寫時可能會出現並發的問題。

4.Broadcast

  Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。

5.AIDL方式

  Service和Content Provider類似,也可以訪問其他應用程序中的數據,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。

         AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。

6.Messenger

  Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。

  雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。

7.Socket

  Socket方法是通過網路來進行數據交換,注意的是要在子線程請求,不然會堵塞主線程。客戶端和服務端建立連接之後即可不斷傳輸數據,比較適合實時的數據傳輸

二、Android線程間通信方式

  一般說線程間通信主要是指主線程(也叫UI線程)和子線程之間的通信,主要有以下兩種方式:

1.AsyncTask機制

  AsyncTask,非同步任務,也就是說在UI線程運行的時候,可以在後台的執行一些非同步的操作;AsyncTask可以很容易且正確地使用UI線程,AsyncTask允許進行後台操作,並在不顯示使用工作線程或Handler機制的情況下,將結果反饋給UI線程。但是AsyncTask只能用於短時間的操作(最多幾秒就應該結束的操作),如果需要長時間運行在後台,就不適合使用AsyncTask了,只能去使用Java提供的其他API來實現。

2.Handler機制

  Handler,繼承自Object類,用來發送和處理Message對象或Runnable對象;Handler在創建時會與當前所在的線程的Looper對象相關聯(如果當前線程的Looper為空或不存在,則會拋出異常,此時需要在線程中主動調用Looper.prepare()來創建一個Looper對象)。使用Handler的主要作用就是在後面的過程中發送和處理Message對象和讓其他的線程完成某一個動作(如在工作線程中通過Handler對象發送一個Message對象,讓UI線程進行UI的更新,然後UI線程就會在MessageQueue中得到這個Message對象(取出Message對象是由其相關聯的Looper對象完成的),並作出相應的響應)。

三、Android兩個子線程之間通信

  面試的過程中,有些面試官可能會問Android子線程之間的通信方式,由於絕大部分程序員主要關注的是Android主線程和子線程之間的通信,所以這個問題很容易讓人懵逼。

  主線程和子線程之間的通信可以通過主線程中的handler把子線程中的message發給主線程中的looper,或者,主線程中的handler通過post向looper中發送一個runnable。但looper默認存在於main線程中,子線程中沒有Looper,該怎麼辦呢?其實原理很簡單,把looper綁定到子線程中,並且創建一個handler。在另一個線程中通過這個handler發送消息,就可以實現子線程之間的通信了。

  子線程創建handler的兩種方式:

  方式一:給子線程創建Looper對象:

new Thread(new Runnable() {

            public void run() { 

                Looper.prepare();  // 給這個Thread創建Looper對象,一個Thead只有一個Looper對象

                Handler handler = new Handler(){ 

                    @Override 

                    public void handleMessage(Message msg) { 

                        Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show(); 

                    } 

                }; 

                handler.sendEmptyMessage(1); 

                Looper.loop(); // 不斷遍歷MessageQueue中是否有消息

            }; 

        }).start();

---------------------

       方式二:獲取主線程的looper,或者說是UI線程的looper:

new Thread(new Runnable() {

            public void run() { 

                Handler handler = new Handler(Looper.getMainLooper()){ // 區別在這!!! 

                    @Override 

                    public void handleMessage(Message msg) { 

                        Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show(); 

                    } 

                }; 

                handler.sendEmptyMessage(1); 

            }; 

        }).start();

---------------------

閱讀全文

與android線程內存相關的資料

熱點內容
pore命令 瀏覽:868
rsa加密上傳圖片 瀏覽:383
香港經典三圾片 瀏覽:749
什麼app可以自己定製鞋子 瀏覽:313
穿越將夜的小說有哪些 瀏覽:908
法國啄木鳥40部電影有哪些 瀏覽:664
主角叫葉無雙的小說 瀏覽:396
程序員總裁肉 瀏覽:900
最短路演算法編程簡單示例 瀏覽:219
訂民宿的app是什麼 瀏覽:653
攝像頭內存卡怎麼解壓 瀏覽:426
命令商 瀏覽:823
伺服器滿了怎麼登上王者搶先服 瀏覽:886
省內物流摩托車用什麼app 瀏覽:762
漫畫素描pdf 瀏覽:17
c語言編譯鏈接怎麼回事 瀏覽:730
七日殺命令台倉庫 瀏覽:128
VS編譯工具的優點 瀏覽:232
android文件擴展 瀏覽:735
快貸app怎麼實名 瀏覽:109