線程概述
線程與進(jìn)程
進(jìn)程
?每個(gè)運(yùn)行中的任務(wù)(通常是程序)就是一個(gè)進(jìn)程。當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成了一個(gè)進(jìn)程。每一個(gè)進(jìn)程都有一定的獨(dú)立功能,進(jìn)程是系統(tǒng)進(jìn)行資源分配與調(diào)度的一個(gè)獨(dú)立單元。
- 獨(dú)立性:進(jìn)程是系統(tǒng)中獨(dú)立存在的實(shí)體,它可以擁有自己獨(dú)立的資源,每一個(gè)進(jìn)程都有自己私有的地址空間。在沒(méi)有進(jìn)程本身允許的條件下,一個(gè)用戶進(jìn)程不可以直接訪問(wèn)其他進(jìn)程的地址空間。
- 動(dòng)態(tài)性:進(jìn)程與程序的區(qū)別在于,程序只是一序列靜態(tài)指令的集合,而進(jìn)程則是正在執(zhí)行中的程序,擁有自己的生命周期和各種不同的狀態(tài),是動(dòng)態(tài)產(chǎn)生、變化以及消亡的。
- 并發(fā)性:多個(gè)進(jìn)程可以在單個(gè)處理器上并發(fā)執(zhí)行,并且不會(huì)互相影響。
- 異步性:由于進(jìn)程的相互制約,使進(jìn)程具有執(zhí)行的間斷性,即進(jìn)程按各自獨(dú)立的、 不可預(yù)知的速度向前推進(jìn)。異步性會(huì)導(dǎo)致執(zhí)行結(jié)果的不可再現(xiàn)性,為此,在操作系統(tǒng)中必須配置相應(yīng)的進(jìn)程同步機(jī)制。
- 結(jié)構(gòu)性:進(jìn)程包含程序及其相關(guān)數(shù)據(jù)結(jié)構(gòu)。進(jìn)程的實(shí)體包含進(jìn)程控制塊(PCB),程序塊、數(shù)據(jù)塊和堆棧,又稱為進(jìn)程映像。
線程
?線程是進(jìn)程的執(zhí)行單元,是進(jìn)程的組成部分,一個(gè)進(jìn)程可以擁有多個(gè)線程,一個(gè)線程必須有一個(gè)父進(jìn)程。線程可以擁有自己的堆棧,自己的程序計(jì)數(shù)器以及自己的局部變量,但不擁有系統(tǒng)資源,它與父進(jìn)程的其它線程共享該進(jìn)程的全部資源。
?一個(gè)線程可以創(chuàng)建和銷(xiāo)毀另一個(gè)線程,同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。
?線程是程序中一個(gè)單一的順序控制流程。進(jìn)程內(nèi)一個(gè)相對(duì)獨(dú)立的、可調(diào)度的執(zhí)行單元,是系統(tǒng)獨(dú)立調(diào)度和分派CPU的基本單位。在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱為多線程。
- 進(jìn)程之間不能共享內(nèi)存,但線程之間共享內(nèi)存非常容易。
- 系統(tǒng)創(chuàng)建一個(gè)進(jìn)程需要為該進(jìn)程分配獨(dú)立的內(nèi)存空間,并分配大量的相關(guān)資源,但創(chuàng)建線程則代價(jià)小得多,因此使用多線程來(lái)實(shí)現(xiàn)多任務(wù)比使用多進(jìn)程的效率高。
- 因?yàn)榫€程劃分的尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。
線程實(shí)現(xiàn)
繼承Thread類(lèi)
- 定義Thread類(lèi)的子類(lèi),并重寫(xiě)run()方法,該run()方法的方法體就代表了線程要完成的任務(wù)即線程的執(zhí)行體;
- 創(chuàng)建Thread子類(lèi)的實(shí)例,即創(chuàng)建線程對(duì)象;
-
調(diào)用線程對(duì)象的start()方法來(lái)啟動(dòng)該線程。(注意,不是直接調(diào)用對(duì)象的run()方法,調(diào)用對(duì)象的run()方法,其實(shí)就相當(dāng)于普通的方法調(diào)用,并不會(huì)創(chuàng)建線程);
通過(guò)繼承Thread類(lèi)實(shí)現(xiàn)線程.png
線程執(zhí)行結(jié)果.png
?從圖中可以看到,程序創(chuàng)建了三個(gè)線程,包含一個(gè)主線程和兩個(gè)子線程。并且可以看到,線程輸出并不是連續(xù)的,這是因?yàn)榫€程的執(zhí)行是基于系統(tǒng)資源調(diào)度執(zhí)行的。
?從圖中可以看出,sum變量不是連續(xù)的。使用繼承Thread的方法來(lái)創(chuàng)建線程類(lèi)時(shí),多個(gè)線程之間無(wú)法共享線程類(lèi)的實(shí)例變量;因?yàn)槊看蝿?chuàng)建線程對(duì)象時(shí)都是需要?jiǎng)?chuàng)建一個(gè)MyThread對(duì)象,每個(gè)對(duì)象都包含自己的實(shí)例變量。
實(shí)現(xiàn)Runnable接口
- 定義實(shí)現(xiàn)Runnable接口的實(shí)現(xiàn)類(lèi),并重寫(xiě)接口的run()方法,該run()方法的方法體就代表了線程要完成的任務(wù)即線程的執(zhí)行體;
- 創(chuàng)建Runnable實(shí)現(xiàn)類(lèi)的實(shí)例,并以此實(shí)例作為T(mén)hread的target來(lái)創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象;
-
調(diào)用Thread對(duì)象的start()方法來(lái)啟動(dòng)該線程。(注意,不是直接調(diào)用Runnable對(duì)象的run()方法,調(diào)用Runnable對(duì)象的run()方法,其實(shí)就相當(dāng)于普通的方法調(diào)用,并不會(huì)創(chuàng)建線程);
通過(guò)實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)線程.png
線程執(zhí)行結(jié)果.png
?從圖中可以看出,sum變量時(shí)連續(xù)的。使用實(shí)現(xiàn)Runnable的方法來(lái)創(chuàng)建線程類(lèi)時(shí),多個(gè)線程之間可以共享線程類(lèi)的實(shí)例變量;因?yàn)樵谶@種方式下,程序所創(chuàng)建的Runnable對(duì)象只是線程的target,而多個(gè)線程可以共享同一個(gè)target,所以多個(gè)線程可以共享同一個(gè)線程類(lèi)(線程的target類(lèi))的實(shí)例變量。
- String getName() : 獲取當(dāng)前線程的名稱;
- void run() : 線程的執(zhí)行體,線程需要完成的任務(wù)都在該方法中實(shí)現(xiàn);
- void start() :線程對(duì)象通過(guò)調(diào)用此方法來(lái)啟動(dòng)線程;
- Thread Thread.currentThread() : 返回當(dāng)前正在執(zhí)行的線程;
通過(guò)Callable和Future創(chuàng)建線程
- 創(chuàng)建Callable接口的實(shí)現(xiàn)類(lèi),并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值;
- 創(chuàng)建Callable實(shí)現(xiàn)類(lèi)的實(shí)例,使用FutureTask類(lèi)來(lái)包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值;
- 使用FutureTask對(duì)象作為T(mén)hread對(duì)象的target創(chuàng)建并啟動(dòng)新線程;
-
調(diào)用FutureTask對(duì)象的get()方法來(lái)獲得子線程執(zhí)行結(jié)束后的返回值,注意不是直接調(diào)用Callable對(duì)象的call()方法獲取返回值,Callable對(duì)象的call()方法為線程的執(zhí)行體被調(diào)用;
通過(guò)Callable和Futrue創(chuàng)建線程.png
線程執(zhí)行結(jié)果.png
?從圖中可以看到當(dāng)主線程的sum變量循環(huán)到20時(shí),程序啟動(dòng)以FutureTask對(duì)象為target的線程,然后通過(guò)調(diào)用FutureTask對(duì)象的get()方法來(lái)獲得call()方法的返回值。該方法將導(dǎo)致程序的主進(jìn)程被阻塞,直到call()方法結(jié)束并返回為止。
Callable 接口方法
- V call() : 線程的執(zhí)行體,線程需要完成的任務(wù)都在該方法中實(shí)現(xiàn),并帶有返回值;
Future接口方法
- V get() : 返回Callable對(duì)象里call()方法的返回值。調(diào)用該方法將導(dǎo)致程序阻塞,必須等待子線程結(jié)束后才回得到返回值;
- V get(long timeout, TimeUnit unit) : 返回Callable對(duì)象里call()方法的返回值。調(diào)用該方法將導(dǎo)致程序最多阻塞timeout和unit指定時(shí)間,如果經(jīng)過(guò)指定時(shí)間后,Callable任務(wù)依然沒(méi)有返回值,則拋出TimeoutException異常;
- boolean cancel(boolean mayInterruptIfRunning) : 試圖取消Future里關(guān)聯(lián)的Callable任務(wù);
- boolean isCancelled() : 如果在Callable任務(wù)正常完成前被取消,返回true;
- boolean isDone() : 如果Callable任務(wù)已完成,返回true;
創(chuàng)建線程三種方式的比較
采用繼承Thread類(lèi)創(chuàng)建線程的優(yōu)缺點(diǎn)
- 劣勢(shì):因?yàn)榫€程類(lèi)已經(jīng)繼承了Thread類(lèi),不能在繼承別的父類(lèi);
- 優(yōu)勢(shì):編寫(xiě)簡(jiǎn)單,如果訪問(wèn)當(dāng)前線程,則無(wú)需使用Thread.currentThrend()方法,直接使用this就可獲得當(dāng)前線程;
采用實(shí)現(xiàn)Runnable,Callable接口創(chuàng)建線程的優(yōu)缺點(diǎn)
- 優(yōu)勢(shì):線程類(lèi)只實(shí)現(xiàn)了Runnable接口或Callable接口,還可以繼續(xù)繼承其他類(lèi);
- 優(yōu)勢(shì):在這種情況下,多個(gè)進(jìn)程可以共享同一個(gè)target對(duì)象,所以非常適合多個(gè)相同的線程來(lái)處理同一份資源的情況,從而可以將CPU、代碼和數(shù)據(jù)分開(kāi),形成清晰的模型,較好的體現(xiàn)了面向?qū)ο蟮乃枷耄?/li>
- 劣勢(shì):編程稍微復(fù)雜,如果需要訪問(wèn)當(dāng)前線程,需要使用Thread.currentThrend()方法獲取;
線程狀態(tài)
- 新建狀態(tài)(NEW)
- 可運(yùn)行狀態(tài)(RUNNABLE)
- 阻塞狀態(tài)(BLOCKED)
- 等待狀態(tài)(WAITING)
- 計(jì)時(shí)等待狀態(tài)(TIMED_WAITING)
- 終止?fàn)顟B(tài)(TERMINATED)
新建狀態(tài)(NEW)
?當(dāng)用new關(guān)鍵字創(chuàng)建一個(gè)新線程時(shí),該線程處于新建狀態(tài)。此時(shí)他和其他的Java對(duì)象一樣,僅僅由JVM為其分配內(nèi)存,并初始化成員變量的值,此時(shí)線程對(duì)象沒(méi)有表現(xiàn)出線程的動(dòng)態(tài)特征,程序也不會(huì)執(zhí)行線程的執(zhí)行體。
可運(yùn)行狀態(tài)(RUNNABLE)
?當(dāng)線程對(duì)象調(diào)用了start()方法后,線程處于runnable狀態(tài),JVM為其創(chuàng)建方法調(diào)用棧和程序計(jì)數(shù)器。處于runnable狀態(tài)的線程,可能正在運(yùn)行也可能沒(méi)有運(yùn)行,這取決于JVM里線程調(diào)度器的調(diào)度,當(dāng)線程獲得CPU時(shí)間片時(shí),線程執(zhí)行。
?當(dāng)一個(gè)線程開(kāi)始運(yùn)行時(shí),它不可能處于一直運(yùn)行的狀態(tài)(除非它的線程執(zhí)行體足夠短,瞬間就執(zhí)行結(jié)束了)。線程在運(yùn)行過(guò)程中需要被中斷,目的是讓其他線程獲得執(zhí)行的機(jī)會(huì),線程調(diào)度的細(xì)節(jié)依賴于操作系統(tǒng)提供的服務(wù)。
阻塞與(計(jì)時(shí))等待狀態(tài)(BLOCKED,WAITING,TIMED_WAITING)
?當(dāng)線程處于阻塞或者等待狀態(tài)時(shí),它暫時(shí)不活動(dòng)。直到線程調(diào)度器重新激活它。細(xì)節(jié)取決于它是怎么達(dá)到非活動(dòng)狀態(tài)的。
- 當(dāng)一個(gè)線程試圖獲取一個(gè)內(nèi)部的對(duì)象鎖(而不是java.util.concurrent庫(kù)中的鎖),而該鎖被其他線程持有時(shí),則該線程進(jìn)入阻塞狀態(tài)。當(dāng)所有其他線程釋放該鎖,并且線程調(diào)度器允許本線程持有它的時(shí)候,該線程將變成非阻塞狀態(tài)。
- 當(dāng)線程等待另一個(gè)線程通知調(diào)度器一個(gè)條件時(shí),它自己進(jìn)入等待狀態(tài)。在調(diào)用Object.wait方法或Thread.join方法,或者是等待java.util.concurrent庫(kù)中的Lock或Condition時(shí),就會(huì)出現(xiàn)這種情況。
- 有幾個(gè)方法有一個(gè)超時(shí)參數(shù)。調(diào)用它們導(dǎo)致線程進(jìn)入計(jì)時(shí)等待狀態(tài)。這一狀態(tài)將一直保持到超時(shí)期滿或者接收到適當(dāng)?shù)耐ㄖв谐瑫r(shí)參數(shù)的方法有Thread.sleep和Object.wait、Thread.join、Lock.tryLock以及Condition.await的計(jì)時(shí)版。
終止?fàn)顟B(tài)(TERMINATED)
?線程因如下原因之一而被終止:(當(dāng)然還有一種調(diào)用stop()方法,不過(guò)該方法已過(guò)時(shí),不建議調(diào)用)
- 因?yàn)閞un()方法或call()方法執(zhí)行完成,結(jié)束后線程就自然死亡。
-
因?yàn)橐粋€(gè)沒(méi)有捕獲的Exception或Error而意外死亡。
線程狀態(tài)轉(zhuǎn)換圖(來(lái)自一哥們).png
Thread 方法
- void join() : 等待終止指定的線程;
- void join(long millis) : 等待指定的線程死亡或者經(jīng)過(guò)指定的毫秒數(shù);
- Thread.State getState() : 得到這一線程的狀態(tài);NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING或者TERMINATED之一;
線程屬性
線程優(yōu)先級(jí)
?每個(gè)線程執(zhí)行都有一定的優(yōu)先級(jí),優(yōu)先級(jí)高的獲得較多的執(zhí)行機(jī)會(huì),優(yōu)先級(jí)低的執(zhí)行機(jī)會(huì)先對(duì)較少。默認(rèn)情況下,一個(gè)線程繼承它的父線程優(yōu)先級(jí);默認(rèn)情況下,main線程具有普通優(yōu)先級(jí),由main創(chuàng)建的線程也具普通優(yōu)先級(jí)。
?Thread類(lèi)提供setPriority(int newPriority),getPriority()方法來(lái)設(shè)置和獲取指定線程的優(yōu)先級(jí)??梢詫?yōu)先級(jí)設(shè)置為MIN_PRIORITY(Thread類(lèi)中定義為1)與MAX_PRIORITY(定義為10)之間的任何值。默認(rèn)NORM_PRIORITY被定義5。
?每當(dāng)線程調(diào)度器有機(jī)會(huì)選擇新線程時(shí),他首先選擇具有高優(yōu)先級(jí)的線程。但是線程優(yōu)先級(jí)是高度依賴于操作系統(tǒng)的。不同操作系統(tǒng)上的優(yōu)先級(jí)并不相同,而且也不能很好的和Java的10個(gè)優(yōu)先級(jí)對(duì)應(yīng)。(例如Windows有7個(gè)優(yōu)先級(jí)。一些Java優(yōu)先級(jí)將映射到相同的操作系統(tǒng)優(yōu)先級(jí)。在Oracle為L(zhǎng)inux提供的Java虛擬機(jī)中,線程的優(yōu)先級(jí)被忽略——所有的線程具有相同的優(yōu)先級(jí)。(來(lái)自Java核心技術(shù) 卷I))。所以應(yīng)盡量避免直接為線程指定優(yōu)先級(jí)。
Thread 方法
- void setPriority(int newPriority) : 設(shè)置線程的優(yōu)先級(jí)。優(yōu)先級(jí)必須在Thread.MIN_PRIORITY與Thread.MAX_PRIORITY之間,一般使用Thread.MIN_PRIORITY優(yōu)先級(jí)。
- static int MIN_PRIORITY : 線程的最小優(yōu)先級(jí),最小優(yōu)先級(jí)的值為1。
- static int NORM_PRIORITY : 線程的默認(rèn)優(yōu)先級(jí),默認(rèn)優(yōu)先級(jí)的值為5。
- static int MAX_PRIORITY : 線程的最大優(yōu)先級(jí),最大優(yōu)先級(jí)的值為10。
- static native void yield() : 導(dǎo)致當(dāng)前執(zhí)行線程處于讓步狀態(tài)。如果其他的可運(yùn)行線程具有至少與此線程同樣高的優(yōu)先級(jí),那么這些線程接下來(lái)會(huì)被調(diào)度。
守護(hù)線程
?可以通過(guò)調(diào)用setDaemon(true)將線程轉(zhuǎn)換為守護(hù)線程。守護(hù)線程的唯一用途就是為其它線程提供服務(wù)。當(dāng)只剩下守護(hù)線程時(shí)虛擬機(jī)就退出了,由于如果只剩下守護(hù)線程,就沒(méi)必要繼續(xù)運(yùn)行程序了。
?守護(hù)線程應(yīng)該永遠(yuǎn)不去訪問(wèn)固有資源,如文件、數(shù)據(jù)庫(kù),因?yàn)樗鼤?huì)在任何時(shí)候甚至在一個(gè)操作的中間發(fā)生中斷。
Thread 方法
- void setDaemon(boolean isDaemon) : 標(biāo)示該線程為守護(hù)線程或者用戶線程。這一方法必須在線程啟動(dòng)之前調(diào)用。
- boolean isDaemon() : 判斷線程是否是守護(hù)線程。
常用方法
- public synchronized void start() : 使該線程開(kāi)始執(zhí)行;Java 虛擬機(jī)調(diào)用該線程的 run 方法。
- public void run() : 線程的執(zhí)行體,線程的執(zhí)行任務(wù)在該方法完成。
- public final synchronized void setName(String name) : 設(shè)置線程的名稱。
- public final void setPriority(int newPriority) : 設(shè)置線程的優(yōu)先級(jí)。
- public final void setDaemon(boolean on) : 將該線程設(shè)置為守護(hù)線程或者用戶線程。守護(hù)線程和用戶線程的區(qū)別在于:守護(hù)線程依賴于創(chuàng)建它的線程,而用戶線程則不依賴。必須在thread.start()之前設(shè)置,否則會(huì)拋出一個(gè)IllegalThreadStateException異常
- public final void join() : 等待該線程終止。
- public final synchronized void join(long millis) : 等待該線程終止的時(shí)間最長(zhǎng)為 millis 毫秒。
- public final synchronized void join(long millis, int nanos) : 等待該線程終止,當(dāng) 999999 > nanos > 500000 時(shí),最長(zhǎng)等待時(shí)間為 millis + 1;當(dāng) millis = 0 && nanos != 0 ,最長(zhǎng)等待時(shí)間為1毫秒。
- public void interrupt() : 向線程發(fā)送中斷請(qǐng)求。線程的中斷狀態(tài)將被設(shè)置為true。如果目前該線程被一個(gè)sleep調(diào)用阻塞,那么將拋出InterruptedException異常。
- public static boolean interrupted() : 測(cè)試當(dāng)前線程(即正在執(zhí)行這一命令的線程)是否被中斷。這一調(diào)用會(huì)產(chǎn)生副作用——它將當(dāng)前線程的中斷狀態(tài)設(shè)置為false。
- public boolean isInterrupted() : 測(cè)試線程是否被終止。這一調(diào)用不會(huì)改變線程的中斷狀態(tài)。
- public final native boolean isAlive() : 測(cè)試線程是否處于活動(dòng)狀態(tài)(線程處于正在運(yùn)行或準(zhǔn)備開(kāi)始運(yùn)行的狀態(tài))。
- public static native void sleep(long millis) : 在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。有一點(diǎn)要非常注意,sleep方法不會(huì)釋放鎖,也就是說(shuō)如果當(dāng)前線程持有對(duì)某個(gè)對(duì)象的鎖,則即使調(diào)用sleep方法,其他線程也無(wú)法訪問(wèn)這個(gè)對(duì)象。如果調(diào)用了sleep方法,必須捕獲InterruptedException異?;蛘邔⒃摦惓O蛏蠈訏伋觥.?dāng)線程睡眠時(shí)間滿后,不一定會(huì)立即得到執(zhí)行,因?yàn)榇藭r(shí)可能CPU正在執(zhí)行其他的任務(wù)。所以說(shuō)調(diào)用sleep方法相當(dāng)于讓線程進(jìn)入阻塞狀態(tài)。
- public static void sleep(long millis, int nanos) : 在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),當(dāng) 999999 > nanos >= 500000 時(shí),暫停時(shí)間為 millis + 1 毫秒,當(dāng) nanos != 0 && millis == 0 暫停時(shí)間為1毫秒。
- public static native void yield() : 導(dǎo)致當(dāng)前執(zhí)行線程處于讓步狀態(tài)。如果有其他可運(yùn)行的線程具有至少與此線程同樣高的優(yōu)先級(jí),那么這些線程接下來(lái)會(huì)被調(diào)度。調(diào)用yield方法會(huì)讓當(dāng)前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類(lèi)似,同樣不會(huì)釋放鎖。但是yield不能控制具體的交出CPU的時(shí)間。調(diào)用yield方法并不會(huì)讓線程進(jìn)入阻塞狀態(tài),而是讓線程重回就緒狀態(tài),它只需要等待重新獲取CPU執(zhí)行時(shí)間,這一點(diǎn)是和sleep方法不一樣的。
- public static native Thread currentThread() : 返回當(dāng)前執(zhí)行線程的Thread對(duì)象。
線程面試
什么是線程?
?線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。
線程與進(jìn)程的區(qū)別?
?進(jìn)程是一個(gè)獨(dú)立的運(yùn)行環(huán)境,它可以被看作是一個(gè)程序或者一個(gè)應(yīng)用。而線程是在進(jìn)程中執(zhí)行的一個(gè)任務(wù)。線程是進(jìn)程的子集,一個(gè)進(jìn)程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進(jìn)程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間。別把它和棧內(nèi)存搞混,每個(gè)線程都擁有單獨(dú)的棧內(nèi)存用來(lái)存儲(chǔ)本地?cái)?shù)據(jù)。
如何在Java中實(shí)現(xiàn)線程?
- 繼承Thread類(lèi);
- 實(shí)現(xiàn)Runnable接口;
- 通過(guò)Callable和Future創(chuàng)建線程;
Thread 類(lèi)中的start() 和 run() 方法有什么區(qū)別?
?start()方法被用來(lái)啟動(dòng)新創(chuàng)建的線程,而且start()內(nèi)部調(diào)用了run()方法,這和直接調(diào)用run()方法的效果不一樣。當(dāng)你調(diào)用run()方法的時(shí)候,只會(huì)是在原來(lái)的線程中調(diào)用,沒(méi)有新的線程啟動(dòng),start()方法才會(huì)啟動(dòng)新線程。
Runnable和Callable有什么不同?
?Runnable和Callable都代表那些要在不同的線程中執(zhí)行的任務(wù)。Runnable從JDK1.0開(kāi)始就有了,Callable是在JDK1.5增加的。它們的主要區(qū)別是Callable的 call() 方法可以返回值和拋出異常,而Runnable的run()方法沒(méi)有這些功能。Callable可以返回裝載有計(jì)算結(jié)果的Future對(duì)象。
Thread類(lèi)的sleep()方法和對(duì)象的wait()方法都可以讓線程暫停執(zhí)行,它們有什么區(qū)別?
?sleep()方法是線程類(lèi)(Thread)的靜態(tài)方法,調(diào)用此方法會(huì)讓當(dāng)前線程暫停執(zhí)行指定的時(shí)間,將執(zhí)行機(jī)會(huì)(CPU)讓給其他線程,但是對(duì)象的鎖依然保持,因此休眠時(shí)間結(jié)束后會(huì)自動(dòng)恢復(fù)(線程回到就緒狀態(tài))。wait()是Object類(lèi)的方法,調(diào)用對(duì)象的wait()方法導(dǎo)致當(dāng)前線程放棄對(duì)象的鎖(線程暫停執(zhí)行),進(jìn)入對(duì)象的等待池,只有調(diào)用對(duì)象的notify()方法(或notifyAll()方法)時(shí)才能喚醒等待池中的線程進(jìn)入等鎖池,如果線程重新獲得對(duì)象的鎖就可以進(jìn)入就緒狀態(tài)。
線程的sleep()方法和yield()方法有什么區(qū)別?
- sleep()方法給其他線程運(yùn)行機(jī)會(huì)時(shí)不考慮線程的優(yōu)先級(jí),因此會(huì)給低優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);yield()方法只會(huì)給相同優(yōu)先級(jí)或更高優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);
- 線程執(zhí)行sleep()方法后轉(zhuǎn)入阻塞狀態(tài),而執(zhí)行yield()方法后轉(zhuǎn)入就緒狀態(tài);
- sleep()方法聲明拋出InterruptedException,而yield()方法沒(méi)有聲明任何異常;
- sleep()方法比yield()方法(跟操作系統(tǒng)CPU調(diào)度相關(guān))具有更好的可移植性。
????整理文章主要為了自己日后復(fù)習(xí)用,文章中可能會(huì)引用到別的博主的文章內(nèi)容,如涉及到博主的版權(quán)問(wèn)題,請(qǐng)博主聯(lián)系我。






