創(chuàng)建后臺(tái)線程的方法有多種,這里說三種,可以回去試試

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、門源網(wǎng)絡(luò)推廣、重慶小程序開發(fā)、門源網(wǎng)絡(luò)營銷、門源企業(yè)策劃、門源品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供門源建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:chinadenli.net
1、使用Android系統(tǒng)工具類 AsyncTask(Params,Progress,Result)
AsyncTask是一個(gè)輕量級(jí)線程,三個(gè)泛型參數(shù)分別是 Params傳入?yún)?shù),int型Progress為進(jìn)度條進(jìn)度,Result為返回值
要使用AsyncTask,必須繼承之并復(fù)寫其中的幾個(gè)重要的函數(shù)。
onPreExecute(), 該方法將在執(zhí)行實(shí)際的后臺(tái)操作前被UI thread調(diào)用。可以在該方法中做一些準(zhǔn)備工作,如在界面上顯示一個(gè)進(jìn)度條。
doInBackground(Params...), 將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運(yùn)行在后臺(tái)線程中。這里將主要負(fù)責(zé)執(zhí)行那些很耗時(shí)的后臺(tái)計(jì)算工作。可以調(diào)用 publishProgress方法來更新實(shí)時(shí)的任務(wù)進(jìn)度。該方法是抽象方法,子類必須實(shí)現(xiàn)。
onProgressUpdate(Progress...),在publishProgress方法被調(diào)用后,UI thread將調(diào)用這個(gè)方法從而在界面上展示任務(wù)的進(jìn)展情況,例如通過一個(gè)進(jìn)度條進(jìn)行展示。
onPostExecute(Result), 在doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調(diào)用,后臺(tái)的計(jì)算結(jié)果將通過該方法傳遞到UI thread.
注:Task必須在UI線程中創(chuàng)建,并調(diào)用并且只能調(diào)用一次execute方法,該方法的參數(shù)為傳入的泛型Params。
其余函數(shù)最好不要手動(dòng)調(diào)用,容易造成線程崩潰。多次調(diào)用Task,容易造成線程池溢出。
2、使用Handler和HandlerThread
誤區(qū): Handler handler = new Handler ();
handler.post(r);
這種做法看似創(chuàng)建了一個(gè)線程,但實(shí)際上handler只是直接調(diào)用Runnable中的run() 方法,而不執(zhí)行線程的start()函數(shù),所以這兩句代碼執(zhí)行后,程序仍然在UI線程中執(zhí)行。所以我們引入HandlerThread,因?yàn)镠andlerThread中有一個(gè)Looper對(duì)象,用以循環(huán)消息隊(duì)列。
為了使用Looper,必須子類化Handler,并復(fù)寫它的構(gòu)造函數(shù)。
class MyHandler extends Handler{
public MyHandler() {}
public MyHandler(Looper looper){
super (looper);
}
public void handleMessage(Message msg){
//....這里運(yùn)行耗時(shí)的過程
}
}
}
handleMessage(Message msg)函數(shù)用以接收消息,msg則是從UI線程中發(fā)出的消息,可以傳遞各種對(duì)象,根據(jù)這些對(duì)象和數(shù)值進(jìn)行操作。
有了Handler子類,則可以在UI線程中進(jìn)行創(chuàng)建和初始化
HandlerThread handlerThread = new HandlerThread( "backgroundThread" );
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//....此處對(duì)msg進(jìn)行賦值,可以創(chuàng)建一個(gè)Bundle進(jìn)行承載
msg.sendToTarget();
之后如果需要調(diào)用線程,只要對(duì)handler傳入msg,就可以執(zhí)行相應(yīng)的過程了
最后,很重要的一點(diǎn),HandlerThread 不隨Activity的生命周期結(jié)束而消亡,所以必須復(fù)寫Ondestory(),調(diào)用HandlerThread .stop()
3、使用線程同步 synchronized、 wait()、 notify()
使用線程同步機(jī)制synchronized實(shí)現(xiàn)多線程操作,相對(duì)來說比較復(fù)雜,但也是靈活性最佳、效率最高的一種做法,在產(chǎn)品開發(fā)當(dāng)中也使用得最廣。本人水平相當(dāng)有限,也只學(xué)得一點(diǎn)皮毛。
synchronized相當(dāng)于一把鎖,當(dāng)線程運(yùn)行的時(shí)候,會(huì)同時(shí)有幾個(gè)線程訪問一個(gè)對(duì)象,對(duì)其進(jìn)行操作或者修改。這可能引起很不良的后果(例如改變判定條件,或者在別的線程還沒使用完的時(shí)候?qū)ο笠呀?jīng)被析構(gòu)等等),所以必須對(duì)一些對(duì)象進(jìn)行加鎖,保證它在同一時(shí)間只允許被一個(gè)線程訪問。
synchronized使用方法有兩種:
1 同步方法在方法名前加入synchronized關(guān)鍵字,則該方法在同一時(shí)間內(nèi)只允許一個(gè)線程訪問它,其代碼邏輯較為簡單,但使用起來不太靈活,并且大大降低效率,耗時(shí)太長的同步方法甚至?xí)沟枚嗑€程失去原本的意義成為單線程
2同步參數(shù) 對(duì)某一個(gè)代碼塊加鎖,并且以synchronized(obj)的方式,表明該代碼塊內(nèi)的obj對(duì)象是線程同步的。這個(gè)做法使得代碼靈活性大大加強(qiáng),縮小同步代碼塊的范圍,并且可以在不同的函數(shù)體和類內(nèi)進(jìn)行同步,唯一遺憾的是實(shí)現(xiàn)起來比較復(fù)雜,容易產(chǎn)生一些問題
而wait()和notify(),必須在synchronized鎖的代碼塊內(nèi)執(zhí)行,否則系統(tǒng)將會(huì)報(bào)錯(cuò)。
有了以上基礎(chǔ),就可以很容易的創(chuàng)建后臺(tái)線程了
Private Runnable backgroundRunnable = new Runnable () {
@Override
public void run() {
if(isFinish){
//.....
break;
}
for(;;){
synchronized(this){
//....寫耗時(shí)過程
wait();
}
}
}
}
UI線程中,就是一般的創(chuàng)建線程過程了
Thread backgroundThread = new Thread (backgroundRunnable);
backgroundThread.start();
這樣,在后臺(tái)線程中會(huì)不斷的循環(huán),當(dāng)執(zhí)行完一次過程以后就會(huì)wait()休眠。然后在OnTouchListener或者OnClickListener內(nèi)相應(yīng)的位置執(zhí)行
synchronized(backgroundRunnable){
backgroundRunnable.notify();
}
當(dāng)用戶觸摸屏幕產(chǎn)生一個(gè)event的時(shí)候,線程就會(huì)被喚醒,執(zhí)行下一次循環(huán)。
最后,還是內(nèi)存安全問題,必須復(fù)寫Activity中的OnDestory()方法,將標(biāo)志量isFinish設(shè)為false,并且backgroundThread .stop()
多線程作為Android開發(fā)中相對(duì)而言較為高階的知識(shí),其中用到相關(guān)的知識(shí)點(diǎn)是非常的多,所以在我們需要進(jìn)行設(shè)計(jì)或者寫多線程的代碼就必須要進(jìn)行相對(duì)謹(jǐn)慎的處理,這樣就由必要對(duì)其要有著比較系統(tǒng)化的認(rèn)知
我們一般將Android應(yīng)用分成為兩種:主線程和工作線程;主線程主要是用來進(jìn)行初始化UI,而工作線程主要是進(jìn)行耗時(shí)操作,例如讀取數(shù)據(jù)庫,網(wǎng)絡(luò)連接等
Android系統(tǒng)是以進(jìn)程為單位來對(duì)應(yīng)用程序資源進(jìn)行限制,這個(gè)問題的可以解釋為:一個(gè)進(jìn)程最多能夠開幾個(gè)線程?最好能開幾個(gè)?但實(shí)則這個(gè)是沒有上限這一說,主要是因?yàn)橘Y源的限制
Android中關(guān)于主線程的理解:Android的主線程是UI線程,在Android中,四大組件運(yùn)行在主線程中,在主線程中做耗時(shí)操作會(huì)導(dǎo)致程序出現(xiàn)卡頓甚至出現(xiàn)ANR異常,一個(gè).
在一個(gè)程序中,這些獨(dú)立運(yùn)行的程序片斷叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理”。多線程處理一個(gè)常見的例子就是用戶界面。
線程總的來就是進(jìn)程的一個(gè)實(shí)體,是CPU進(jìn)行分派和調(diào)度的基本單位,擁有著比進(jìn)程更小且能夠獨(dú)立運(yùn)行的基本單位,線程本身基本上是不擁有系統(tǒng)資源,僅擁有一點(diǎn)在運(yùn)行過程中必須擁有的資源,但它可與同屬一個(gè)進(jìn)程中的其他進(jìn)程進(jìn)行共享其所擁有的所有資源
線程狀態(tài)有些地方將之分為5中狀態(tài),而且在Java Jdk中線程被其定義為6中狀態(tài),我們可以對(duì)其進(jìn)行類比
普遍定義的5中狀態(tài):新建,就緒,運(yùn)行,阻塞, 死亡
Java Jdk 定義狀態(tài)
線程阻塞是指在某一時(shí)刻的某一個(gè)線程在進(jìn)行運(yùn)行一段代碼的情況下,突然另一個(gè)線程也要進(jìn)行運(yùn)行,但在運(yùn)行過程中,那個(gè)線程執(zhí)行完全運(yùn)行之前,另一個(gè)線程是不可能獲取到CPU的執(zhí)行權(quán),就會(huì)導(dǎo)致線路阻塞的出現(xiàn)
死鎖也稱之為抱死,意思就是說一個(gè)進(jìn)程鎖定了另外一個(gè)進(jìn)程所需要的頁或表是,但第二個(gè)進(jìn)程同時(shí)又鎖定了第一個(gè)進(jìn)程所需的一頁,這樣就會(huì)出現(xiàn)死鎖現(xiàn)象
簡要介紹實(shí)現(xiàn)線程的三種方式:繼承Thread,實(shí)現(xiàn)runnable,實(shí)現(xiàn)callable。這里有一點(diǎn)需要注意的是,實(shí)現(xiàn)callable是與線程池相關(guān)聯(lián)的而callable很重要的一個(gè)特性是其帶有返回值。當(dāng)我們只需實(shí)現(xiàn)單線程時(shí)實(shí)現(xiàn)runnable更加利于線程程序的拓展
在線程開啟之前進(jìn)行調(diào)用 thread.setDaemon(true); 將thread設(shè)定成當(dāng)前線程中的守護(hù)線程 使用案例
線程讓步【yield方法】讓當(dāng)前線程釋放CPU資源,讓其他線程搶占
這種具體某個(gè)對(duì)象鎖 wait notify 方法與Condition 的 await以及signal方法類似; 全面這種方法的阻塞等待都可以是釋放鎖,而且在喚醒后,這種線程都是能夠獲取鎖資源的,而這個(gè)門栓就跟閥門類似
本來開辟一個(gè)新的線程是屬于子線程,但是你的Handler是跟主線程綁定的。嚴(yán)格來說是在子線程中運(yùn)行。
handler是android特有的機(jī)制,最大的好處就是實(shí)現(xiàn)了Activity主線程(就是UI主線程)和其他線程(自己定義的Thread)之間的數(shù)據(jù)通信。Timer和Thread是實(shí)現(xiàn)多線程的,而handler是實(shí)現(xiàn)線程間通信的,二者很大不同,關(guān)于handler的用法
在一個(gè)程序中,這些獨(dú)立運(yùn)行的程序片斷叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理”。多線程處理一個(gè)常見的例子就是用戶界面。利用線程,用戶可按下一個(gè)按鈕,然后程序會(huì)立即作出響應(yīng),而不是讓用戶等待程序完成了當(dāng)前任務(wù)以后才開始響應(yīng)。簡單地說,就是說可以有多個(gè)任務(wù)同時(shí)進(jìn)行。
單線程在程序執(zhí)行時(shí),所走的程序路徑按照連續(xù)順序排下來,前面的必須處理好,后面的才會(huì)執(zhí)行。因此,針對(duì)前面舉的例子,必須等待程序完成了當(dāng)前任務(wù)以后才能開始相應(yīng)。
使用多線程訪問公共的資源時(shí),容易引發(fā)線程安全性問題,因此針對(duì)這種需要使用線程同步機(jī)制來保護(hù)公共的資源。
單線程較多線程來說,就不會(huì)出現(xiàn)上訴問題,系統(tǒng)穩(wěn)定、擴(kuò)展性極強(qiáng)、軟件豐富。多用于點(diǎn)對(duì)點(diǎn)的服務(wù)。
異步通信機(jī)制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實(shí)現(xiàn) 工作線程對(duì)UI的更新處理,最終實(shí)現(xiàn)異步消息的處理。Handler不僅僅能將子線程的數(shù)據(jù)傳遞給主線程,它能實(shí)現(xiàn)任意兩個(gè)線程的數(shù)據(jù)傳遞。
(1)Message
Message 可以在線程之間傳遞消息。可以在它的內(nèi)部攜帶少量數(shù)據(jù),用于在不同線程之間進(jìn)行數(shù)據(jù)交換。除了 what 字段,還可以使用 arg1 和 arg2 來攜帶整型數(shù)據(jù),使用 obj 來攜帶 Object 數(shù)據(jù)。
(2) Handler
Handler 作為處理中心,用于發(fā)送(sendMessage 系列方法)與處理消息(handleMessage 方法)。
(3) MessageQueue
MessageQueue 用于存放所有通過 Handler 發(fā)送的消息。這部分消息會(huì)一直存放在消息隊(duì)列中,直到被處理。每個(gè)線程中只會(huì)有一個(gè) MessageQueue 對(duì)象
(4) Looper
Looper 用于管理 MessageQueue 隊(duì)列,Looper對(duì)象通過loop()方法開啟了一個(gè)死循環(huán)——for (;;){},不斷地從looper內(nèi)的MessageQueue中取出Message,并傳遞到 Handler 的 handleMessage() 方法中。每個(gè)線程中只會(huì)有一個(gè) Looper 對(duì)象。
AsyncTask 是一種輕量級(jí)的任務(wù)異步類,可以在后臺(tái)子線程執(zhí)行任務(wù),且將執(zhí)行進(jìn)度及執(zhí)行結(jié)果傳遞給 UI 線程。
(1)onPreExecute()
在 UI 線程上工作,在任務(wù)執(zhí)行 doInBackground() 之前調(diào)用。此步驟通常用于設(shè)置任務(wù),例如在用戶界面中顯示進(jìn)度條。
(2)doInBackground(Params... params)
在子線程中工作,在 onPreExecute() 方法結(jié)束后執(zhí)行,這一步被用于在后臺(tái)執(zhí)行長時(shí)間的任務(wù),Params 參數(shù)通過 execute(Params) 方法被傳遞到此方法中。任務(wù)執(zhí)行結(jié)束后,將結(jié)果傳遞給 onPostExecute(Result) 方法,同時(shí)我們可以通過 publishProgress(Progress) 方法,將執(zhí)行進(jìn)度發(fā)送給 onProgressUpdate(Progress) 方法。
(3)onProgressUpdate(Progress... values)
在 UI 線程上工作,會(huì)在 doInBackground() 中調(diào)用 publishProgress(Progress) 方法后執(zhí)行,此方法用于在后臺(tái)計(jì)算仍在執(zhí)行時(shí)(也就是 doInBackgound() 還在執(zhí)行時(shí))將計(jì)算執(zhí)行進(jìn)度通過 UI 顯示出來。例如,可以通過動(dòng)畫進(jìn)度條或顯示文本字段中的日志,從而方便用戶知道后臺(tái)任務(wù)執(zhí)行的進(jìn)度。
(4)onPostExecute(Result result)
在 UI 線程上工作,在任務(wù)執(zhí)行完畢(即 doInBackground(Result) 執(zhí)行完畢)并將執(zhí)行結(jié)果傳過來的時(shí)候工作。
使用規(guī)則:
(1)AsyncTask 是個(gè)抽象類,所以要?jiǎng)?chuàng)建它的子類實(shí)現(xiàn)抽象方法
(1)AsyncTask 類必須是在 UI 線程中被加載,但在Android 4.1(API 16)開始,就能被自動(dòng)加載完成。
(2)AsyncTask 類的實(shí)例對(duì)象必須在 UI 線程中被創(chuàng)建。
(3)execute() 方法必須是在 UI 線程中被調(diào)用。
(4)不要手動(dòng)調(diào)用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()
(5)任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行,將拋出異常)。即一個(gè)AsyncTask對(duì)象只能調(diào)用一次execute()方法。
原理:
? ? ? 其源碼中原理還是 Thread 與 Handler 的實(shí)現(xiàn),其包含 兩個(gè)線程池,一個(gè) Handler,如下所示:
名稱類型作用
SERIAL_EXECUTOR線程池分發(fā)任務(wù),串行分發(fā),一次只分發(fā)一個(gè)任務(wù)
THREAD_POOL_EXECUTOR線程池執(zhí)行任務(wù),并行執(zhí)行,執(zhí)行的任務(wù)由 SERIAL_EXECUTOR 分發(fā)
InternalHandlerHandler負(fù)責(zé)子線程與主線程的溝通,通知主線程做 UI 工作
一方面減少了每個(gè)并行任務(wù)獨(dú)自建立線程的開銷,另一方面可以管理多個(gè)并發(fā)線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務(wù)的執(zhí)行。Executors利用工廠模式對(duì)ThreadPoolExecutor進(jìn)行了封裝。
Executors提供了四種創(chuàng)建ExecutorService的方法,他們的使用場景如下:
1. Executors.newFixedThreadPool()
創(chuàng)建一個(gè)定長的線程池,每提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到達(dá)到池的最大長度,這時(shí)線程池會(huì)保持長度不再變化。
當(dāng)線程處于空閑狀態(tài)時(shí),它們并不會(huì)被回收,除非線程池被關(guān)閉。當(dāng)所有的線程都處于活動(dòng)狀態(tài)時(shí),新任務(wù)都會(huì)處于等待狀態(tài),直到有線程空閑出來。
只有核心線程并且不會(huì)被回收,能夠更加快速的響應(yīng)外界的請(qǐng)求。
2. Executors.newCachedThreadPool()
創(chuàng)建一個(gè)可緩存的線程池,如果當(dāng)前線程池的長度超過了處理的需要時(shí),它可以靈活的回收空閑的線程,當(dāng)需要增加時(shí),它可以靈活的添加新的線程,而不會(huì)對(duì)池的長度作任何限制
線程數(shù)量不定的線程池,只有非核心線程,最大線程數(shù)為 Integer.MAX_VALUE。當(dāng)線程池中的線程都處于活動(dòng)狀態(tài)時(shí),線程池會(huì)創(chuàng)建新的線程來處理新任務(wù),否則利用空閑的線程來處理新任務(wù)。線程池中的空閑線程具有超時(shí)機(jī)制,為 60s。
任務(wù)隊(duì)列相當(dāng)于一個(gè)空集合,導(dǎo)致任何任務(wù)都會(huì)立即被執(zhí)行,適合執(zhí)行大量耗時(shí)較少的任務(wù)。當(dāng)整個(gè)線程池都處于限制狀態(tài)時(shí),線程池中的線程都會(huì)超時(shí)而被停止。
3. Executors.newScheduledThreadPool()
創(chuàng)建一個(gè)定長的線程池,而且支持定時(shí)的以及周期性的任務(wù)執(zhí)行,類似于Timer。
非核心線程數(shù)沒有限制,并且非核心線程閑置的時(shí)候立即回收,主要用于執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。
4. Executors.newSingleThreadExecutor()
創(chuàng)建一個(gè)單線程化的executor,它只創(chuàng)建唯一的worker線程來執(zhí)行任務(wù)
只有一個(gè)核心線程,保證所有的任務(wù)都在一個(gè)線程中順序執(zhí)行,意義在于不需要處理線程同步的問題。
一般用于執(zhí)行后臺(tái)耗時(shí)任務(wù),當(dāng)任務(wù)執(zhí)行完成會(huì)自動(dòng)停止;同時(shí)由于它是一個(gè)服務(wù),優(yōu)先級(jí)要遠(yuǎn)遠(yuǎn)高于線程,更不容易被系統(tǒng)殺死,因此比較適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)。
使用步驟:創(chuàng)建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執(zhí)行耗時(shí)任務(wù)
原理:在源碼實(shí)現(xiàn)上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結(jié)束后會(huì)調(diào)用IntentService的stopSelf(int startId)方法嘗試停止服務(wù)。
IntentService的內(nèi)部是通過消息的方式請(qǐng)求HandlerThread執(zhí)行任務(wù),HandlerThread內(nèi)部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執(zhí)行后臺(tái)任務(wù)的
(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個(gè)工作線程(非UI線程)+任務(wù)的等待隊(duì)列的形式,優(yōu)點(diǎn)是不會(huì)有堵塞,減少了對(duì)性能的消耗,缺點(diǎn)是不能同時(shí)進(jìn)行多個(gè)任務(wù)的處理,需要等待進(jìn)行處理。處理效率低,可以當(dāng)成一個(gè)輕量級(jí)的線程池來用)
網(wǎng)站標(biāo)題:android多線程機(jī)制,andriod 多線程
分享路徑:http://chinadenli.net/article2/dsggooc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、服務(wù)器托管、用戶體驗(yàn)、自適應(yīng)網(wǎng)站、網(wǎng)站導(dǎo)航、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)