Android中有關線程Thread等相關知識的筆記
線程Thread
每個應用程序在創建時都會默認運行單一的進程,其中包含所有的任務。爲避免用戶界面被掛起,那些耗時的任務 ,諸如網絡下載或密集的計算,應當駐留於單獨的後臺線程中,如何適當地實現這種操作由開發者決定,但之後則是由Android系統基於開發者的實現來確定線程的優先級。
大多數應用程序都通過使用線程來提升性能。如果用戶界面的掛起在軟件設計階段沒有被發覺,到了測試階段就會迅速體現出來,因爲Android系統會在用戶界面掛起時彈出警告—告訴用戶Slow app isn’t responding.
Android Thread的使用方法:
Thread的使用方法主要有兩種方法:其中一種是extends Thread,然後重載Thread的run()函數,另一種是構建一個新的Thread對象,可帶Runnable或不帶。但不管怎麼樣,都是要通過start()函數來運行相應的代碼
構建Thread對象的方法如下:
1、Thread()不代任何參數,該方法會在構建的時候自動生成線程名字。
舉例:
Thread mThread = new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread_test");
super.run();
}
};
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:22:08.692: INFO/System.out(831): Thread-10
04-27 09:22:08.702: INFO/System.out(831): This is thread_test
2、Thread(Runnable runnable)該函數多了Runnable個對象,被運行的代碼在Runnable對象裏。
舉例:
Runnable mRunnable = new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread with Runnable");
}
};
Thread mThread = new Thread(mRunnable);
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:37:47.832: INFO/System.out(865): Thread-11
04-27 09:37:47.861: INFO/System.out(865): This is thread with Runnable
3、Thread(Runnable runnable,String threadName)該函數有Runnable也有自己的名字threadName。
舉例:
Runnable mRunnable = new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread with Runnable and Name");
}
};
Thread mThread = new Thread(mRunnable,"mThreadTest");
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:44:03.682: INFO/System.out(900): mThreadTest
04-27 09:44:03.702: INFO/System.out(900): This is thread with Runnable and Name
Runable和Thread的關係
在java中可有兩種方法實現多線程,一種是繼承Thread類,一種是實現Runnable接口;
1)繼承Thread類的方式
Thread類是在java.lang包中定義的 。一個類只要繼承了Thread類同時覆寫了本類中的run()
步驟就可以實現多線程操作了,然而一個類只能繼承一個父類,這是此種方法的的侷限 。 下面看例子:
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);
}
}
}
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1=new MyThread("線程a");
MyThread mt2=new MyThread("線程b");
mt1.start();
mt2.start();
}
}
2) Runnable接口
在實際開闢中一個多線程的操作很少 使用Thread類,而是通過Runnable接口實現 。 public interface Runnable{ public void run(); }
例子:
class MyThread implements Runnable{
private String name;
public MyThread(String name) {
this.name = name;
}
public void run(){
for(int i=0;i<100;i++){
System.out.println("線程開端:"+this.name+",i="+i);
}
}
};
然而在Runnable的子類中沒有start() 方法,只有Thread類中才有 。此時視察Thread類,有一個構造函數:public Thread(Runnable targer) 此構造函數接受Runnable的子類實例,也就是說可以通過Thread類來啓動Runnable實現多線程 。(start() 可以協調系統的資源):
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1=new MyThread("線程a");
MyThread mt2=new MyThread("線程b");
new Thread(mt1).start();
new Thread(mt2).start();
}
}
3)實際中如何應用這兩種實現模式
在程序實現多線程應優先以實現Runnable接口爲主,由於實現Runnable接口相比繼承Thread類有如下好處:
1.避免點繼承的侷限,一個類可以繼承多個接口 。
2. 利於資源的共享。
以賣票程序爲例,通過Thread類實現:
class MyThread extends Thread {
private int ticket=10;
public void run(){
for(int i=0;i<20;i++) {
if(this.ticket>0){
System.out.println("賣票:ticket"+this.ticket--);
}
}
}
};
下面通過三個線程對象,同時賣票:
public class ThreadTicket {
public static void main(String[] args) {
MyThread mt1=new MyThread();
MyThread mt2=new MyThread();
MyThread mt3=new MyThread();
mt1.start();//每個線程都各賣了10張,共賣了30張票
mt2.start();//但實際只有10張票,每個線程都賣自己的票
mt3.start();//沒有達到資源共享
}
}
假如用Runnable就 可以實現資源共享,下面看例子:
class MyThread implements Runnable{
private int ticket=10;
public void run(){
for(int i=0;i<20;i++){
if(this.ticket>0){
System.out.println("賣票:ticket"+this.ticket--);
}
}
}
}
public class RunnableTicket {
public static void main(String[] args) {
MyThread mt=new MyThread();
new Thread(mt).start();//同一個mt
new Thread(mt).start();
new Thread(mt).start();
}
};
現在程序中有三個線程,然而一共賣了10張票,也就是說使用Runnable實現多線程可以達到資源共享的目的。
4)Runnable接口和Thread的關係總結
(1) 說白了就是類和接口的區別。Thread是一個類,java中是不允許繼承多個父類的,這就是Thread的一個侷限性。而使用Runnable就不同了,可以implements多個接口,同時繼承一個父類,這樣會更加靈活。
(2) 當多個線程需要共享資源時,用Thread很難達到目的,但是用Runnable接口就容易許多了。
(3) 二者的聯繫:看源碼可以發現,Thread其實就是繼承了Runnable接口的子類。
取消線程
有時,當一個組件完成或被殺死是,開發者希望有它產生的線程也同樣被殺死,例如在某個Acitivity中定義了線程:
private …Thread myThread;
myThread.stop()方法已經被棄用了,因爲它會將應用程序置於不可預知的狀態,取而代之的是下面的方法,比如在父組件的onStop()方法中加入
if(myThread != null){
Thread dummy = myThread;
myThread = null;
dummy.interrupt();
}
在應用程序層面上還有另外一種方法來完成相同的工作:使用setDaemon(true)方法將所有生成的線程都聲明爲守護線程,可以確保所有與應用程序關聯的線程在應用程序的主線程終結時,也隨之被殺死。
//use when initially starting a thread
myThread。setDaemon(true);
myThread.start();
設置線程的優先級
Android系統會處理線程的優先級,默認情況下,一個新線程,如myThread,其優先級被定爲5。開發者可以在myThread.start()執行之前,通過調用myThread.setPriority(priority)來爲線程設定另外的優先級。優先級不能高於Thread.MAX_PRIORITY(10)或者低於Thread.MIN_PRIORITY(1)
Android還提供了另一種設定線程優先級的方法通過android.os.Process.setThreadPriority (int tid, int priority)
priority:【-20, 19】,高優先級 -> 低優先級。在實際操作中,因爲setThreadPriority 是一個基於“良好的”Linux值得優先級,可以設定的粒度更細,並且對線程的影響也更加明顯。