首先,要辨析進程與線程的概念:
進程是程序執(zhí)行的過程,它持有資源和線程,相對于程序本身而言具有動態(tài)性。
線程是系統(tǒng)中最小的執(zhí)行單元,同一個進程中可能有多個線程,它們共享該進程持有的資源。線程的通信也稱為線程的交互,方式主要有互斥和同步。同步是指線程之間通過共同協(xié)作完成某項工作,線程間具有次序性;互斥是指線程間對某一資源的競爭,一次只能有一個線程訪問該資源。
介紹完了這些基本概念,下面簡單介紹一下Java對多線程的支持.
java中通過類Thread和接口Runnable來實現(xiàn)多線程的操作。它們都有一個run方法來指定線程工作時執(zhí)行的代碼。
Thread類的常用方法
| 類別 | 名稱 | 簡介 | 
| 線程的創(chuàng)建 | Thread() | |
| Thread(String name) | ||
| Thread(Runnable target) | ||
| Thread(Runnable target, String name) | ||
| 線程的方法 | void start() | 啟動線程 | 
| static void sleep(long millis) | 線程休眠 | |
| static void sleep(long millis, int nanos) | ||
| void join() | 某線程調用join方法后,使其他線程等待該線程終止 | |
| void join(long millis) | ||
| void join(long millis, int nanos) | ||
| static void yield() | 當前正在運行的線程立刻釋放處理器,重新加入競爭處理器的隊列 | |
| 獲取線程引用 | static Thread currentThread() | 返回當前正在運行的線程的引用 | 
使用多線程有兩種方式,一種是直接繼承Thread類,一種是實現(xiàn)Runnable接口
另外,通過volatile關鍵字聲明的成員變量可以保證當其他線程修改該成員變量后,本線程可以正確讀取到此成員變量的值。
線程的狀態(tài)請結合OS中進程的5態(tài)來思考。以下線程狀態(tài)和方法的介紹來自DreamSea(張小哲)

Ø線程的方法(Method)、屬性(PRoperty)
1)優(yōu)先級(priority)
每個類都有自己的優(yōu)先級,一般property用1-10的整數表示,默認優(yōu)先級是5,優(yōu)先級最高是10;優(yōu)先級高的線程并不一定比優(yōu)先級低的線程執(zhí)行的機會高,只是執(zhí)行的機率高;默認一個線程的優(yōu)先級和創(chuàng)建他的線程優(yōu)先級相同;
2)Thread.sleep()/sleep(long millis)
當前線程睡眠/millis的時間(millis指定睡眠時間是其最小的不執(zhí)行時間,因為sleep(millis)休眠到達后,無法保證會被JVM立即調度);sleep()是一個靜態(tài)方法(static method) ,所以他不會停止其他的線程也處于休眠狀態(tài);線程sleep()時不會失去擁有的對象鎖。 作用:保持對象鎖,讓出CPU,調用目的是不讓當前線程獨自霸占該進程所獲取的CPU資源,以留一定的時間給其他線程執(zhí)行的機會;
3)Thread.yield()
讓出CPU的使用權,給其他線程執(zhí)行機會、讓同等優(yōu)先權的線程運行(但并不保證當前線程會被JVM再次調度、使該線程重新進入Running狀態(tài)),如果沒有同等優(yōu)先權的線程,那么yield()方法將不會起作用。
4)thread.join()
使用該方法的線程會在此之間執(zhí)行完畢后再往下繼續(xù)執(zhí)行。
5)object.wait() 當一個線程執(zhí)行到wait()方法時,他就進入到一個和該對象相關的等待池(Waiting Pool)中,同時失去了對象的機鎖—暫時的,wait后還要返還對象鎖。當前線程必須擁有當前對象的鎖,如果當前線程不是此鎖的擁有者,會拋出IllegalMonitorStateException異常,所以wait()必須在synchronized block中調用。sleep()和wait()方法的最大區(qū)別是:sleep()睡眠時,保持對象鎖,仍然占有該鎖;而wait()睡眠時,釋放對象鎖。但是wait()和sleep()都可以通過interrupt()方法打斷線程的暫停狀態(tài),從而使線程立刻拋出InterruptedException(但不建議使用該方法)。
6)object.notify()/notifyAll()
喚醒在當前對象等待池中等待的第一個線程/所有線程。notify()/notifyAll()也必須擁有相同對象鎖,否則也會拋出IllegalMonitorStateException異常。
7)Synchronizing Block
Synchronized Block/方法控制對類成員變量的訪問;Java中的每一個對象都有唯一的一個內置的鎖,每個Synchronized Block/方法只有持有調用該方法被鎖定對象的鎖才可以訪問,否則所屬線程阻塞;機鎖具有獨占性、一旦被一個Thread持有,其他的Thread就不能再擁有(不能訪問其他同步方法),方法一旦執(zhí)行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執(zhí)行狀態(tài)。正確停止Java線程非正確停止的方法:stop()
要正確停止線程,應該使用正確的退出標記。正常情況下run方法執(zhí)行完畢線程就停止了,但是有些情況下run方法中需要while循環(huán)保持輪詢,所以應該為while循環(huán)設置合適的退出條件,即退出標記,保證線程正確停止。
或者使用interrupt()方法的初衷并不是要停止線程,正常情況下,調用該方法可以將中斷標記設置為TRUE。但是,當某個線程因為調用了wait()或者sleep()等方法而被阻塞時,此時調用interrupt()方法并不能正確的將interrupted標記設置為TRUE,并且同時會拋出中斷異常。
爭用條件:當多個線程同時共享訪問同一個內存數據時,每個線程都嘗試操作該數據,從而導致數據被破壞。
線程的互斥與同步互斥是指在同一時刻只有一個線程可以對臨界區(qū)進行操作。在JAVA中,可以通過synchronized塊或者方法來實現(xiàn)。
在synchronized塊中,需要對某個對象進行加鎖,并將需要互斥的代碼放入synchronized塊中,從而來實現(xiàn)互斥行為。獲得該鎖的進程可以進入該synchronized塊中.
而同步則是線程之間的一種通信機制,通過同步可以規(guī)定線程執(zhí)行的順序。例如,當線程不滿足訪問某資源時,可以通過調用鎖對象的lock.wait()方法,使該線程讓出CPU,讓出鎖,并在該鎖對象的waitset中等待。滿足條件時,可以通過lock.notify()方法隨機喚醒一條線程,lock.notifyAll()則喚醒該waitset中所有的線程,使它們重新競爭該鎖。被喚醒的線程從wait()方法處繼續(xù)執(zhí)行。
新聞熱點
疑難解答