Android Handler Runnable和Thread之间的区别和联系详解
在java中可有兩種方式實現(xiàn)多線程,一種是繼承Thread類,一種是實現(xiàn)Runnable接口;Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()方法就可以實現(xiàn)多線程操作了,但是一個類只能繼承一個父類,這是此方法的局限。
下面看例子:
- package?org.thread.demo; ?
- class?MyThread?extends?Thread{ ?
- private?String?name; ?
- public?MyThread(String?name)?{ ?
- super(); ?
- this.name?=?name; ?
- } ?
- public?void?run(){ ?
- for(int?i=0;i<10;i++){ ?
- System.out.println("線程開始:"+this.name+",i="+i); ?
- } ?
- } ?
- } ?
- package?org.thread.demo; ?
- public?class?ThreadDemo01?{ ?
- public?static?void?main(String[]?args)?{ ?
- MyThread?mt1=new?MyThread("線程a"); ?
- MyThread?mt2=new?MyThread("線程b"); ?
- mt1.run(); ?
- mt2.run(); ?
- } ?
- }
但是,此時結(jié)果很有規(guī)律,先第一個對象執(zhí)行,然后第二個對象執(zhí)行,并沒有相互運行。在JDK的文檔中可以發(fā)現(xiàn),一旦調(diào)用start()方法,則會通過JVM找到run()方法。下面啟動start()方法啟動線程:
這樣程序可以正常完成交互式運行。那么為啥非要使用start();方法啟動多線程呢?
在JDK的安裝路徑下,src.zip是全部的java源程序,通過此代碼找到Thread中的start()方法的定義,可以發(fā)現(xiàn)此方法中使用了private native void start0();其中native關(guān)鍵字表示可以調(diào)用操作系統(tǒng)的底層函數(shù),那么這樣的技術(shù)成為JNI技術(shù)(java Native Interface)
Runnable接口
在實際開發(fā)中一個多線程的操作很少使用Thread類,而是通過Runnable接口完成。
例子:
但是在使用Runnable定義的子類中沒有start()方法,只有Thread類中才有。此時觀察Thread類,有一個構(gòu)造方法:public Thread(Runnable targer)此構(gòu)造方法接受Runnable的子類實例,也就是說可以通過Thread類來啟動Runnable實現(xiàn)的多線程。(start()可以協(xié)調(diào)系統(tǒng)的資源):
兩種實現(xiàn)方式的區(qū)別和聯(lián)系:
在程序開發(fā)中只要是多線程肯定永遠(yuǎn)以實現(xiàn)Runnable接口為主,因為實現(xiàn)Runnable接口相比繼承Thread類有如下好處:
- 避免點繼承的局限,一個類可以繼承多個接口。
- 適合于資源的共享
以賣票程序為例,通過Thread類完成:
下面通過三個線程對象,同時賣票:
如果用Runnable就可以實現(xiàn)資源共享,下面看例子:
雖然現(xiàn)在程序中有三個線程,但是一共賣了10張票,也就是說使用Runnable實現(xiàn)多線程可以達(dá)到資源共享目的。
Runnable接口和Thread之間的聯(lián)系:
public class Thread extends Object implements Runnable
發(fā)現(xiàn)Thread類也是Runnable接口的子類。
第二:
Thread是系統(tǒng)給你的資源,有了Thread你才有從CPU那里得到可執(zhí)行時間片的權(quán)力, Thread并不認(rèn)識你的程序,不知道有test 這樣的類,因為編序員有千千萬,每個人命名都不一樣,想要做的事都不一樣, 所以 Thread只認(rèn)識一個! 那就是Runnable 。 Thread認(rèn)識Runnable 并且知道Runnable 里面有一個run方法. 一旦調(diào)用Thread的start方法,Runnable 方法里的run就會被Thread自動運行。 所以,當(dāng)我們把我們的類繼承(這里應(yīng)該叫實現(xiàn)接口)自Runnable 的時候,我們的程序就是屬于Runnable 一個類型的了。 雖然是Runnable 的子類,但人家認(rèn)識你爸爸,當(dāng)然也知道了你。 Thread可以不管你內(nèi)部有什么情況,他只管你有run()方法就行了,他就調(diào)start讓你去運行run 所以我們在run里面寫點東西,這樣就可以讓系統(tǒng)運行我們想要做的代碼了。 是不是很通俗很易懂呢? 所以要運行線程的步驟是, 1。生成我們自己的類對象 2。從系統(tǒng)那里得到Thread 3。讓Threa調(diào)我們的類對象,讓其start起來 代碼: test a=new test(); Thread thread=new Thread(a); //Thread需要一個參數(shù),就是你編的線程類,這樣他就認(rèn)識了你的線程,也有資格向系統(tǒng)申請拿到CPU時間片thread.start(); 你可以簡單點寫: new Thread(a).start();第三:
Runnable 并不一定是新開一個線程,比如下面的調(diào)用方法就是運行在UI主線程中的:
???? Handler mHandler=new Handler(); mHandler.post(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub } });官方對這個方法的解釋如下,注意其中的:“The runnable will be run?on the user interface thread.?”
boolean android.view.View .post(Runnable action)
Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.
Parameters:
action The Runnable that will be executed.
Returns:
Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.
我們可以通過調(diào)用handler的post方法,把Runnable對象(一般是Runnable的子類)傳過去;handler會在looper中調(diào)用這個Runnable的Run方法執(zhí)行。
Runnable是一個接口,不是一個線程,一般線程會實現(xiàn)Runnable。所以如果我們使用匿名內(nèi)部類是運行在UI主線程的,如果我們使用實現(xiàn)這個Runnable接口的線程類,則是運行在對應(yīng)線程的。
具體來說,這個函數(shù)的工作原理如下:
View.post(Runnable)方法。在post(Runnable action)方法里,View獲得當(dāng)前線程(即UI線程)的Handler,然后將action對象post到Handler里。在Handler里,它將傳遞過來的action對象包裝成一個Message(Message的callback為action),然后將其投入UI線程的消息循環(huán)中。在Handler再次處理該Message時,有一條分支(未解釋的那條)就是為它所設(shè),直接調(diào)用runnable的run方法。而此時,已經(jīng)路由到UI線程里,因此,我們可以毫無顧慮的來更新UI。
如下圖,前面看到的代碼,我們這里Message的callback為一個Runnable的匿名內(nèi)部類
這種情況下,由于不是在新的線程中使用,所以千萬別做復(fù)雜的計算邏輯。
第四:在多線程編程這塊,我們經(jīng)常要使用Handler,Thread和Runnable這三個類,那么他們之間的關(guān)系你是否弄清楚了呢?
首先說明Android的CPU分配的最小單元是線程,Handler一般是在某個線程里創(chuàng)建的,因而Handler和Thread就是相互綁定的,一一對應(yīng)。
而Runnable是一個接口,Thread是Runnable的子類。所以說,他倆都算一個進(jìn)程。
HandlerThread顧名思義就是可以處理消息循環(huán)的線程,他是一個擁有Looper的線程,可以處理消息循環(huán)。
與其說Handler和一個線程綁定,不如說Handler是和Looper一一對應(yīng)的。
最后需要說明的是,在UI線程(主線程)中:
mHandler=new Handler();
mHandler.post(new Runnable(){
void run(){
//執(zhí)行代碼...
}
});
這個線程其實是在UI線程之內(nèi)運行的,并沒有新建線程。
常見的新建線程的方法是:
Thread thread = new Thread();
thread.start();
HandlerThread thread = new HandlerThread("string");
thread.start();
第五: Java ?Runnable接口在進(jìn)行相關(guān)編寫的時候需要我們不斷的學(xué)習(xí)相關(guān)代碼。下面我們就來看炫如何才能使用相關(guān)的代碼。Runnable接口只有一個方法run(),我們聲明自己的類實現(xiàn)Runnable接 口并提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務(wù)。但是Runnable接口并沒有任何對線程的支持,我們還必須創(chuàng)建Thread類 的實例,這一點通過Thread類的構(gòu)造函數(shù)public Thread(Runnable target);來實現(xiàn)。下面是一個例子:
1.public class MyThread implements Runnable
2.{
3.int count= 1, number;
4.public MyThread(int num)
5.{
6.numnumber = num;
7.System.out.println("創(chuàng)建線程 " + number);
8.}
9.public void run()
10.{
11.while(true)
12.{
13.System.out.println
14.("線程 " + number + ":計數(shù) " + count);
15.if(++count== 6) return;
16.}
17.}
18.public static void main(String args[])
19.{
20.for(int i = 0; i 〈 5;
21.i++) new Thread(new MyThread(i+1)).start();
22.}
23.}
嚴(yán)格地說,創(chuàng)建Thread子類的實例也是可行的,但是必須注意的是,該子類必須沒有覆蓋 Thread 類的 run 方法,否則該線程執(zhí)行的將是子類的 run 方法,而不是我們用以實現(xiàn)Runnable 接口的類的 run 方法,對此大家不妨試驗一下。
使用?Java?Runnable接口來實現(xiàn)多線程使得我們能夠在一個類中包容所有的代碼,有利于封裝,它的缺點在于,我們只能使用一套代碼,若想創(chuàng)建多個線程并使各個線程執(zhí)行不同的代 碼,則仍必須額外創(chuàng)建類,如果這樣的話,在大多數(shù)情況下也許還不如直接用多個類分別繼承 Thread 來得緊湊。
參考:
http://www.cnblogs.com/qingblog/archive/2012/08/08/2628245.html
http://java.chinaitlab.com/net/807900.html
http://czhjchina.blog.163.com/blog/static/20027904720111153382495/
http://zhidao.baidu.com/question/82198667.html
http://developer.51cto.com/art/201203/321042.htm
轉(zhuǎn)自:http://blog.csdn.net/yanzi1225627/article/details/8582081
總結(jié)
以上是生活随笔為你收集整理的Android Handler Runnable和Thread之间的区别和联系详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android JNI(Java Nat
- 下一篇: Android 多线程之Handler