進(jìn)程與線程
進(jìn)程是程序的一次動態(tài)執(zhí)行過程,進(jìn)程就是執(zhí)行中的程序活動凝赛,他需要執(zhí)行從代碼加載,代碼執(zhí)行坛缕,到執(zhí)行完畢的一套完整過程墓猎,這個(gè)過程也是進(jìn)程本身從產(chǎn)生,發(fā)展到消亡的過程赚楚,多進(jìn)程操作系統(tǒng)同時(shí)能運(yùn)行多個(gè)進(jìn)程(程序)毙沾,由于CPU具有分時(shí)機(jī)制,所以每個(gè)進(jìn)程都能循環(huán)獲得CPU分配的事件片宠页,由于CPU的處理效率非常的快左胞,所以看起來像每個(gè)進(jìn)程(程序)都在同時(shí)進(jìn)行(單CPU為并發(fā))
線程是實(shí)現(xiàn)并發(fā)機(jī)制的一個(gè)有效手段寇仓,進(jìn)程和線程都是實(shí)現(xiàn)并發(fā)的基本單位,線程是比進(jìn)程很小的執(zhí)行單位烤宙,線程是在進(jìn)程的基礎(chǔ)之上再進(jìn)行的一步劃分遍烦,所謂多線程是指一個(gè)進(jìn)程在執(zhí)行過程可以產(chǎn)生多個(gè)更小的執(zhí)行單元——線程,一個(gè)進(jìn)程可能包含多個(gè)同時(shí)運(yùn)行的線程
按我自己的理解就是躺枕,進(jìn)程并不能多個(gè)進(jìn)程同時(shí)運(yùn)行服猪,只能通過CPU的分時(shí)機(jī)制,“看起來像是在同時(shí)運(yùn)行”(單CPU)拐云,其實(shí)并有沒而,在進(jìn)程中的多線程罢猪,也是并發(fā)的
在Java中實(shí)現(xiàn)多線程有兩種方式,一種是通過繼承Thread類叉瘩,另一種方法是實(shí)現(xiàn)Runnable接口
1.實(shí)現(xiàn)Runnable接口
public class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口膳帕,作為線程的實(shí)現(xiàn)類
? ? private String name ;? ? ? // 表示線程的名稱
? ? public MyThread(String name){
? ? ? ? this.name = name ;? ? ? // 通過構(gòu)造方法配置name屬性
? ? }
? ? public void run(){? // 覆寫run()方法,作為線程 的操作主體
? ? ? ? for(int i=0;i<10;i++){
? ? ? ? ? ? System.out.println(name + "運(yùn)行薇缅,i = " + i) ;
? ? ? ? }
? ? }
}
//使用測試類來展示結(jié)果(新建測試類)
public class RunnableDemo{
? ? public static void main(String args[]){
? ? ? ? MyThread mt1 = new MyThread("線程A ") ;? ? // 實(shí)例化對象
? ? ? ? MyThread mt2 = new MyThread("線程B ") ;? ? // 實(shí)例化對象
? ? ? ? Thread t1 = new Thread(mt1) ;? ? ? // 實(shí)例化Thread類對象
? ? ? ? Thread t2 = new Thread(mt2) ;? ? ? // 實(shí)例化Thread類對象
? ? ? ? t1.start() ;? ? // 啟動多線程
? ? ? ? t2.start() ;? ? // 啟動多線程
? ? }
};
接口Runnable里面要實(shí)現(xiàn)的抽象方法run()
2.通過繼承Thread
class MyThread extends Thread{ // 繼承Thread類备闲,作為線程的實(shí)現(xiàn)類
? ? private String name ;? ? ? // 表示線程的名稱
? ? public MyThread(String name){
? ? ? ? this.name = name ;? ? ? // 通過構(gòu)造方法配置name屬性
? ? }
? ? public void run(){? // 覆寫run()方法,作為線程 的操作主體
? ? ? ? for(int i=0;i<10;i++){
? ? ? ? ? ? System.out.println(name + "運(yùn)行捅暴,i = " + i) ;
? ? ? ? }
? ? }
};
//新建一個(gè)ThreadDemo類來測試結(jié)果
public class ThreadDemo{
? ? public static void main(String args[]){
? ? ? ? MyThread mt1 = new MyThread("線程A ") ;? ? // 實(shí)例化對象
? ? ? ? MyThread mt2 = new MyThread("線程B ") ;? ? // 實(shí)例化對象
? ? ? ? mt1.start() ;? // 調(diào)用線程主體
? ? ? ? mt2.start() ;? // 調(diào)用線程主體
? ? }
};
可以看到恬砂,線程A和線程B是交錯運(yùn)行的,那個(gè)線程搶到了CPU資源蓬痒,哪個(gè)線程就會運(yùn)行泻骤,在線程啟動雖然調(diào)用的是 start() 方法,但實(shí)際上調(diào)用的卻是 run() 方法定義的主體梧奢。
線程的狀態(tài)變化
要想實(shí)現(xiàn)多線程狱掂,必須在主線程中創(chuàng)建新的線程對象,任何線程一般具有五種狀態(tài)亲轨,即創(chuàng)建趋惨,就緒,運(yùn)行惦蚊,阻塞器虾,終止
創(chuàng)建狀態(tài)?
在程序中用構(gòu)造方法創(chuàng)建了一個(gè)線程對象后,新的線程對象便處于新建狀態(tài)蹦锋,此時(shí)它已經(jīng)有了相應(yīng)的內(nèi)存空間和其他資源兆沙,但還處于不可運(yùn)行狀態(tài)。新建一個(gè)線程對象可采用Thread 類的構(gòu)造方法來實(shí)現(xiàn)莉掂,例如 “Thread thread=new Thread()”葛圃。
就緒狀態(tài)?
新建線程對象后,調(diào)用該線程的 start() 方法就可以啟動線程。當(dāng)線程啟動時(shí)库正,線程進(jìn)入就緒狀態(tài)曲楚。此時(shí),線程將進(jìn)入線程隊(duì)列排隊(duì)褥符,等待 CPU 服務(wù)洞渤,這表明它已經(jīng)具備了運(yùn)行條件。
運(yùn)行狀態(tài)?
當(dāng)就緒狀態(tài)被調(diào)用并獲得處理器資源時(shí)属瓣,線程就進(jìn)入了運(yùn)行狀態(tài)载迄。此時(shí),自動調(diào)用該線程對象的 run() 方法抡蛙。run() 方法定義該線程的操作和功能护昧。
阻塞狀態(tài)?
一個(gè)正在執(zhí)行的線程在某些特殊情況下,如被人為掛起或需要執(zhí)行耗時(shí)的輸入/輸出操作粗截,會讓 CPU 暫時(shí)中止自己的執(zhí)行惋耙,進(jìn)入阻塞狀態(tài)。在可執(zhí)行狀態(tài)下熊昌,如果調(diào)用sleep(),suspend(),wait() 等方法绽榛,線程都將進(jìn)入阻塞狀態(tài),發(fā)生阻塞時(shí)線程不能進(jìn)入排隊(duì)隊(duì)列婿屹,只有當(dāng)引起阻塞的原因被消除后灭美,線程才可以轉(zhuǎn)入就緒狀態(tài)。
死亡狀態(tài)?
線程調(diào)用 stop() 方法時(shí)或 run() 方法執(zhí)行結(jié)束后昂利,即處于死亡狀態(tài)届腐。處于死亡狀態(tài)的線程不具有繼續(xù)運(yùn)行的能力。