一、進程與線程
進程:是程序的一次執(zhí)行過程,從代碼加載、執(zhí)行到執(zhí)行完畢的一個完整過程,這個過程也是進程本身從產(chǎn)生、發(fā)展到最后消亡的過程。
一個進程就代表一個程序。操作系統(tǒng)能運行多個同時進程。多進程是實現(xiàn)并發(fā)的一種有效手段。
線程:線程和進程一樣,都是實現(xiàn)并發(fā)的一個基本單位。線程是在進程的基礎(chǔ)上進行的進一步的劃分。
多線程是說一個進程在執(zhí)行過程中可以產(chǎn)生多個線程,這些線程可以同時存在、同在運行。
二、java中線程的實現(xiàn)
第一種:繼承Thread類,重寫run()方法,此方法為線程的主體,
要開啟線程需要調(diào)用start()方法,而不能直接調(diào)用run()方法,若直接調(diào)用run()方法不會開啟線程,仍然是在單線程里執(zhí)行。
為什么啟動線程不能直接使用run()方法呢?
因為線程的運行需要本機操作系統(tǒng)的支持。下面為start()方法在Thread類中的定義:
	public synchronized void start(){		if(threadStatus != 0)			throw new IllegalThreadStateException();		...		start0();		...	}	PRivate native void start0();一般在重復(fù)調(diào)用start()方法時會拋出“IllegalThreadStateException”異常,
而且實際上此處真正調(diào)用的是start0()方法,此方法在聲明處使用的native關(guān)鍵字聲明,此關(guān)鍵字表示調(diào)用本機的操作系統(tǒng)函數(shù),因為多線程的實現(xiàn)依靠底層操作系統(tǒng)的支持。
第二種:實現(xiàn)Runnable接口
Runnable接口中只定義了run()一個抽象方法。
三、Thread和Runnable
聯(lián)系:Thread類實現(xiàn)了Runnable接口,下面是Thread類的定義:

由此可見,Thread類中的run()方法調(diào)用的是Runnable接口中的run()方法,若是要繼承Thread類實現(xiàn)多線程,則必需覆寫run()方法。
區(qū)別:
繼承Thread類不適合多個線程共享資源,因為每創(chuàng)建一個線程對象,每個對象都有自己的屬性、方法,也都有自己的run()方法。
實現(xiàn)Runnable接口,方便實現(xiàn)資源共享:可以使用一個實現(xiàn)Runnable接口的類的對象創(chuàng)建多個線程,它們共用一個Runnable對象,共用里面的屬性、方法,共用run()方法。
四、線程的狀態(tài)
1.創(chuàng)建狀態(tài):創(chuàng)建一個線程對象后就進入創(chuàng)建狀態(tài),此時它已經(jīng)有了相應(yīng)的內(nèi)存空間和其他資源,處于不可運行狀態(tài)。
2.就緒狀態(tài):調(diào)用start()方法后就開啟了線程,線程進入就緒狀態(tài),進入線程隊列排隊,等待CPU服務(wù),已經(jīng)具備運行條件。
3.運行狀態(tài):處于就緒狀態(tài)的線程被調(diào)用并獲得處理器資源時,就進入運行狀態(tài),自動調(diào)用線程對象的run()方法。
4.阻塞狀態(tài):正在運行的線程,被人為掛起或執(zhí)行一些耗時的輸入輸出操作時,讓出CPU,并暫時中止自己的執(zhí)行,進入阻塞狀態(tài)。阻塞時不會進入線程隊列排隊,直到引起阻塞的事件消除后才進入就緒狀態(tài)。
5.終止狀態(tài):線程調(diào)用stop()方法或run()方法結(jié)束后,處于死亡狀態(tài),不能再繼續(xù)執(zhí)行。
五、線程操作的相關(guān)方法
操作線程的主要方法在Thread類中:


1.取得和設(shè)置線程的名稱
Thread類可以通過getName()取得線程的名稱,通過setName()設(shè)置線程的名稱。
線程的名稱一般在啟動線程前設(shè)置,也允許為已經(jīng)運行的線程設(shè)置名稱,如果沒有設(shè)置名稱,系統(tǒng)會為其自動分配名稱,格式為Thread-X。
Java程序每次運行至少啟動幾個線程?
每當(dāng)使用Java命令啟動一個程序時,都會啟動一個JVM,每一個JVM就是操作系統(tǒng)的一個進程,Java本身就具備了垃圾收集機制,所以在Java運行時至少開啟兩個線程,一個是main線程,一個是垃圾收集線程。
2.判斷線程是否啟動
isAlive():判斷線程是否活著(已經(jīng)啟動且尚未運行結(jié)束)
主線程可能比其他線程先執(zhí)行完,此時其他線程不會受影響,不會隨著主線程的結(jié)束而結(jié)束。
3.線程的強制運行
在線程操作中,可以使用join()方法讓一個線程強制運行,在哪個線程里調(diào)用join()方法,就阻塞哪個線程,直到被調(diào)用的線程執(zhí)行結(jié)束,才繼續(xù)執(zhí)行原先的線程。
4.線程的休眠
當(dāng)線程A正在運行時,另一個線程B可以通過調(diào)用線程A的interrupt()方法中斷A的運行;
如果線程的休眠被中斷,則被中斷線程會拋出InterruptedException異常。
5.后臺線程
在Java程序中,只要前臺有一個線程在運行,則整個Java進程都不會消失,若設(shè)置一個后臺線程,這樣即使Java進程結(jié)束了,此后臺線程仍然會繼續(xù)執(zhí)行,setDaemon()方法可將一個線程設(shè)為后臺線程。
6.線程的優(yōu)先級
所有的線程在運行前都保持在就緒狀態(tài),那么此時,哪個優(yōu)先級高,哪個線程就有可能被調(diào)用。
通過setPriority()設(shè)置線程的優(yōu)先級,通過getPriority()獲取線程的優(yōu)先級,線程的優(yōu)先級的級別有以下三種:

class ThreadTask implements Runnable{	public void run() {		for(int i=0;i<5;i++){			try {				Thread.sleep(1000);			} catch (Exception e) {			}				System.out.println(Thread.currentThread().getName()+"-->"+i);		}	}}public class Main {	public static void main(String[] args){		Thread t1 = new Thread(new ThreadTask(),"threadA");		Thread t2 = new Thread(new ThreadTask(),"threadB");		Thread t3 = new Thread(new ThreadTask(),"threadC");		t1.setPriority(Thread.MAX_PRIORITY);		t2.setPriority(Thread.NORM_PRIORITY);		t3.setPriority(Thread.MIN_PRIORITY);		t1.start();		t2.start();		t3.start();			}}運行結(jié)果:threadA-->0threadC-->0threadB-->0threadA-->1threadB-->1threadC-->1threadA-->2threadB-->2threadC-->2threadB-->3threadC-->3threadA-->3threadB-->4threadA-->4threadC-->4線程會根據(jù)其優(yōu)先級的大小來決定哪一個線程先運行,但并非是優(yōu)先級高的就一定會先執(zhí)行,哪個線程先執(zhí)行最終由CPU的調(diào)度決定。
主線程的優(yōu)先級是NORM_PRIORITY,通過getPriority()返回的值為5,是中等級別。
7.線程的礼讓
線程yield()方法可以讓暫停一個線程的操作,讓給其他線程運行,但是暫停的時長是不確定的。
新聞熱點
疑難解答