Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 多線程開發(一)-安卓系統的線程

多線程開發(一)-安卓系統的線程

編輯:關於Android編程

第1節 線程概述

安卓應用只有一個主線程-各個組件都是在這個線程中運行。作為組件的之一的Activity就是在這個線程中更新應用界面的,例如,用戶點擊界面上的一個按鈕,按鈕得到響應,整個過程就是在這個主線程裡。所以這個主線程絕對不可以做耗時的操作。假如在按鈕中做了耗時的操作,那麼當它進行耗時操作的時候,你去點擊界面上的其它按鈕是不會有反應的,就好像程序凍在了那裡。

我們的代碼一旦連續占用這個線程超過一定的時間,系統就會彈出“程序無響應的”提示,這個提示叫做ANR-Applicatin No Response。

\

這就好比你在正在做一件事情A,突然另一件事情B來打擾你,你不得不停下手頭的工作來完成,做完了才能繼續之前的工作;這時如果有另外一個人(另一個線程)來幫助你,把事情B全部包攬了,那你就不用分心了。當另一個人把事情B做完後,告訴你一聲就可以了。

啟動一個新的線程,分擔耗時工作的方法是一種異步操作:我讓你幫我做一件事情,布置任務後,我就去做其他的事情了,等你做完了再告訴我結果;

與它對應的是同步操作:我讓你幫我做一件事情,布置任務後,我啥也不做,就等著你做完了告訴我結果;

\

例如,一個視頻播放應用,獲取視頻信息所需要的時間是個不能確定的事情。如果視頻很少,也許幾十毫秒就能完成,如果視頻很多(比如幾十個),也許就要花二十多秒。

因此,我們可以考慮把獲取視頻信息的操作放到一個單獨的線程thread中進行。啟動一個新線程-工作線程thread-查詢視頻信息,查詢完成後,工作線程再將結果通知到主線程,讓主線程將查詢到結果的結果顯示到界面上。因為界面的更新一定要在主線程中進行,不能在別的線程修改,否則系統後提示運行錯誤。因此我們一定要將查詢的結果發送給主線程,讓主線程處理界面的更新。

這裡就涉及到了線程的創建,工作分配,以及它們之間的配合-信息的傳遞。

第2節 線程Thread

一個Activity運行在一個主線程上,它不能進行耗時巨大的操作,也不能執行耗時不確定的操作。因此需要在新的線程中進行這些耗時的操作,這種進行耗時操作的線程稱作工作線程。

2.1 Thread的簡單使用

創建一個新的線程,

創建一個Runnable,重寫它的run()函數,這個函數裡用來進行耗時的操作;


    @Override
    public void run() {
        //耗時的操作   
        while(xxx)
        {

        }
    }
};

Runnable為參數,創建一個Thread,調用Threadstart()方法後,新線程就運行起來了,並執行Runnable中的run()函數;

Thread thread = new Thread(runnable);
thread.start();

run()函數執行完畢後,新線程就退出;

在線程執行耗時操作的過程中,有時要取消這個線程的操作,

最好的辦法是在run()函數中增加一個標志位,工作線程會隨時檢查這個標志位是否被設置上,如果設置上了,就讓run()函數,立即返回,

//設置標志位,為退出線程使用
boolean needStop = false;
......
Runnable runnable = new Runnable() {

    @Override
    public void run() {
        //耗時的操作
        while(!needStop)
        {

        }  
    }
};

如果主線程要取消這個線程的工作,修改這個標志位就好了,

needStop = true;

2.2 Thread的創建

Thread可以擁有不同的優先級,從低到高有10級。操作系統根據線程的優先級來進行資源調度,優先為優先級高的線程分配CPU資源。在默認情況下,新創建的線程使用默認的優先級NORM_PRIORITY。設置優先級的方式很簡單,

Thread thread = new Thread(runnable);
thread.setPriority(Thread.NORM_PRIORITY);

可以為線程取名字,當我們用Android Monitor工具調試應用的時候,就能看到創建線程時它的名字,方便我們觀察、調試程序,

Thread thread = new Thread(runnable, "新線程的名字");
\

有時,一個應用會同時啟動多個Thread,在創建它們的時候可以為它們設置ThreadGroup參數,將它們分成一組,便於對這些線程進行統一的管理。比如,中斷這個組裡所有線程的運行;

ThreadGroup group = new ThreadGroup("線程組");
Thread thread1 = new Thread(runnable, group);
thread1.start();
Thread thread2 = new Thread(runnable, group);
thread2.start();
Thread thread3 = new Thread(runnable, group);
thread3.start();

//中斷3個線程的執行
group.interrupt();

2.3 Thread的停止

Thread的停止就是指這個線程的退出。線程的退出原因無外乎兩種,

工作線程的工作完成了; 工作線程雖然正在進行耗時工作,但是被取消了,要提前結束;

2.3.1 正常退出

Runnable中的run()函數執行完並返回後,當前的Thread就退出了。

2.3.2 使用標志位

run()函數中增加一個標志位,工作線程會隨時檢查這個標志位是否被設置上,如果設置上了,就讓run()函數,立即返回,

//設置標志位,為退出線程使用
boolean needStop = false;
......
Runnable runnable = new Runnable() {

    @Override
    public void run() {
        //耗時的操作
        while(!needStop)
        {

        }  
    }
};

如果主線程要取消這個線程的工作,修改這個標志位就好了,

needStop = true;

2.3.3 使用interrupt()方法

interrupt()是線程提供的一個標准的線程退出方法,如果當前的工作線程正被Object.waitThread.joinThread.sleep阻塞,那麼使用thread.interrupt()之後,正在運行的線程會拋出一個InterruptedException異常,

Runnable runnable = new Runnable() {

    @Override
    public void run() {
        ...

        while(!needStop)
        {

            try {
                ......
                Sleep(1000); 

            } catch ( InterruptedException e ) {  
                needStop = true
            }

        }
    }
};

不過interrupt()方法並不是萬能的,不是所有阻塞情況下都能夠讓線程立即退出。

例如當該線程正在用ServerSocketaccept()方法等待連接的時候,即使調用了這個工作線程的interrupt()方法,該線程還是不會拋出異常的。

它只對Object.waitThread.joinThread.sleep這幾種阻塞有效果。對於網絡讀取數據時代阻塞狀態解除是沒有效果的。

*對於網絡讀取數據時造成的阻塞,我們會在以後相應的章節詳細介紹解決方法。

2.4 線程之間的同步

線程間的同步就是指線程A執行到一個地方的時候,停了下來,等待線程B的執行結果;等線程B執行出結果後,線程A才能繼續執行。

2.4.1 join()方法

最常見的就是主線程的執行,依賴於工作線程的退出。

主線程啟動了工作線程以後,有時候需要等到工作線程結束以後再進行接下來的操作。

例如一個Activity,在onCreate()的時候創建了一個工作線程Thread B;後來在用戶的要求下,Activity退出,要被銷毀了;銷毀Activity時,主線程要等到Thread B執行完了才能繼續接著進行剩下的清理工作,那麼Activity可以在它的onDestroy()函數中可以使用join()方法,等待子線程的結束,

\
private Thread mTreadB;

@Override
protected void onCreate() {
    super.onCreate();

    mThreadB = new Thread(runnable);
    mThreadB.start();
}

@Override
protected void onDestroy() {
    super.onDestroy();

    mThreadB.join();
    //進行剩下的清理操作
}

join()方法,會一直處於阻塞狀態,直到線程B退出。

onDestroy()中使用join()有天生的缺點:不能在主線程中進行耗時不可控的操作(例如這裡等待工作線程執行完畢),萬一工作線程的退出花費了很長的時間,那就有問題了。這裡的場景只是用來舉一個例子而已。

2.4.2 wait()方法

利用Objectwait()方法實現線程間的同步,需要線程之間共享一個“鎖”-Object對象。

final Object lock = new Object();

當主線程A執行到一個階段的時候,如果要等待線程B,就把鎖置於等待狀態,

lock.wait()

此時,線程A就出於阻塞的狀態,不能往下執行了。

線程B繼續它的運行,當它執行到一個階段的時候,將鎖設置成放行狀態,

lock.notify();

此時,線程A的阻塞狀態解除,可以繼續往下執行了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved