剛開始學(xué)一門編程語言的時候,我總是會有一種困惑,怎樣讓自己的代碼看起來更“專業(yè)”?很多時候,我們可以照著教材實現(xiàn)一些基本的功能,比如用Socket發(fā)送/接收幾個字符,寫一個線程完成某個異步任務(wù),但是在實際的項目中,往往不那么簡單,比如需要設(shè)計Socket通信協(xié)議,需要處理Socket的連接異常斷開,需要考慮在線程阻塞的情況下如何正常退出和釋放資源等等,關(guān)于這些“實戰(zhàn)經(jīng)驗”,前面的文章也有所涉及,以后有空準備再開個專題跟大家分享探討一下,今天先簡單地說說怎樣更“專業(yè)”地在Android程序中處理多線程。
創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來,先為安居等服務(wù)建站,安居等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為安居企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
下面假設(shè)實現(xiàn)一個簡單的定時任務(wù),每秒鐘打印一條Log信息,看看實現(xiàn)這樣一個多線程程序,有哪些需要注意的地方,關(guān)鍵點都以注釋的形式添加到代碼中了。
package com.ticktick.testthread; import android.util.Log; public class PrintThread implements Runnable { private Thread mThread; private boolean mIsThreadStarted = false; private volatile boolean mIsThreadExit = false; //關(guān)鍵1:定義一個volatile類型的條件變量,用于線程的退出 public void startPrintThread() { if( mIsThreadStarted ) { return; } mIsThreadExit = false; mThread = new Thread(this); //關(guān)鍵2:每次啟動都重新創(chuàng)建新的Thread對象,因為一個Thread只能被start一次 mThread.start(); mIsThreadStarted = true; Log.d("PrintThread", "Timer Started"); } public void stopPrintThread() { if( !mIsThreadStarted ) { return; } mIsThreadExit = true; //關(guān)鍵3:通知線程退出循環(huán) mThread.interrupt(); //關(guān)鍵4:調(diào)用interrupt,防止線程內(nèi)部處于sleep或者wait等阻塞狀態(tài) //不過注意,對于socket.accept這樣的阻塞,thread.interrupt是沒有辦法的,但可以用socket.close來喚醒 try { mThread.join(1000); //關(guān)鍵5:調(diào)用join,等待線程真正地完成退出,建議給出一個等待超時時間 } catch (InterruptedException e) { e.printStackTrace(); } mIsThreadStarted = false; Log.d("PrintThread", "Thread Stopped"); } public boolean isThreadStarted() { return mIsThreadStarted; } @Override public void run() { Log.d("PrintThread", "Thread Run Enter !"); while( !mIsThreadExit ) { Log.d("PrintThread", "Thread Arrived !"); try { Thread.sleep(1000); //關(guān)鍵6:線程循環(huán)中,建議使用sleep,讓其他線程可以競爭CPU,sleep(0)代表立即重新競爭一次CPU } catch (InterruptedException e) { e.printStackTrace(); //這里可以直接跳出循環(huán),也可以忽略它而再次檢查條件變量 mIsThreadExit } } Log.d("PrintThread", "Thread Run Exit !"); } }
其實,不僅是Java線程,C/C++的多線程也應(yīng)該注意這幾個關(guān)鍵點,這里再總結(jié)一下:
(1)要定義一個volatile類型的條件變量,決定是否退出線程的死循環(huán)
(2)線程循環(huán)中,最好有sleep延時函數(shù),讓其他線程有機會競爭CPU
(3)要停止線程執(zhí)行,需要做三件事,1. 置位線程退出的條件變量;2. 通過類似interrupt或者socket.close 的調(diào)用,喚醒線程中的阻塞;3. 通過join函數(shù),等待線程真正退出,然后再釋放其他相關(guān)資源
曾經(jīng)在項目中,沒有通過join等待線程退出,導(dǎo)致經(jīng)常會在軟件退出的時候莫名其妙地crash,因此,現(xiàn)在格外注意這一點,而且習(xí)慣性在線程結(jié)束的地方打印出調(diào)試信息,以保證程序中開啟的所有線程都正常地銷毀了。
關(guān)于線程的處理就分享到這里啦,希望對初學(xué)者有幫助,有任何疑問歡迎留言或者來信lujun.hust@gmail.com交流。