溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么創(chuàng)建Thread類

發(fā)布時(shí)間:2021-12-22 17:03:56 來(lái)源:億速云 閱讀:146 作者:iii 欄目:云計(jì)算

這篇文章主要介紹“怎么創(chuàng)建Thread類”,在日常操作中,相信很多人在怎么創(chuàng)建Thread類問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么創(chuàng)建Thread類”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

線程的基本概念

進(jìn)程(Process)是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。程序只是一組指令的有序集合,它本身沒(méi)有任何運(yùn)行的含義,只是一個(gè)靜態(tài)實(shí)體。而進(jìn)程則不同,它是程序在某個(gè)數(shù)據(jù)集上的執(zhí)行,是一個(gè)動(dòng)態(tài)實(shí)體。它因創(chuàng)建而產(chǎn)生,因調(diào)度而運(yùn)行,因等待資源或事件而被處于等待狀態(tài),因完成任務(wù)而被撤消,反映了一個(gè)程序在一定的數(shù)據(jù)集上運(yùn)行的全部動(dòng)態(tài)過(guò)程。

線程(Thread)是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位。線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。

線程和進(jìn)程的關(guān)系是:線程是屬于進(jìn)程的,線程運(yùn)行在進(jìn)程空間內(nèi),同一進(jìn)程所產(chǎn)生的線程共享同一內(nèi)存空間,當(dāng)進(jìn)程退出時(shí)該進(jìn)程所產(chǎn)生的線程都會(huì)被強(qiáng)制退出并清除。線程可與屬于同一進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源,但是其本身基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的信息(如程序計(jì)數(shù)器、一組寄存器和棧)。

要理解多線程的概念,就要首先明白它所帶來(lái)的好處,假設(shè)沒(méi)有線程的概念存在,那么當(dāng)一個(gè)應(yīng)用程序在執(zhí)行時(shí),如果需要多個(gè)分支程序能夠同時(shí)處理數(shù)據(jù),就需要再開(kāi)啟一個(gè)進(jìn)程,

例如:要想同時(shí)執(zhí)行多個(gè)JAVA文件的main方法,那豈不是要啟動(dòng)多個(gè)JAVA虛擬機(jī)才可以?每個(gè)虛擬機(jī)都要為它分配一塊內(nèi)存,計(jì)數(shù)器、寄存器等等,這樣消耗系統(tǒng)資源的話,操作系統(tǒng)是肯定不樂(lè)意的!為了能夠同時(shí)運(yùn)行多個(gè)分支程序又不至于大動(dòng)干戈,所以才有了線程的概念,線程的開(kāi)啟相對(duì)來(lái)說(shuō)是較容易的,它是在進(jìn)程內(nèi)完成的。操作系統(tǒng)不會(huì)再給它分配一塊內(nèi)存,數(shù)據(jù)區(qū)等,所以說(shuō)一個(gè)進(jìn)程當(dāng)中的所有線程都是共享內(nèi)存的。

線程之間的切換

由于現(xiàn)在的操作系統(tǒng)都是支持多進(jìn)程和多線程的。(早先的電腦例如DOS系統(tǒng)是不支持多進(jìn)程的,就是說(shuō)同一時(shí)間只能有一個(gè)程序在運(yùn)行)而CPU的數(shù)量永遠(yuǎn)是有限的,雖然隨著硬件的發(fā)展,一臺(tái)電腦的CPU數(shù)量變的越來(lái)越多,但永遠(yuǎn)也無(wú)法達(dá)到每一個(gè)程序分配一個(gè)CPU的程度。因此操作系統(tǒng)必須要將有限的CPU資源對(duì)應(yīng)用程序進(jìn)行合理的分配。也就是說(shuō),多個(gè)程序搶一個(gè)CPU的話,大家就要輪流執(zhí)行,也就存在了進(jìn)程之間的切換,同樣多個(gè)線程之間也需要切換。線程之間的切換相對(duì)進(jìn)程來(lái)說(shuō)開(kāi)銷是比較小的。所以它被認(rèn)為是輕量級(jí)的。

如何啟動(dòng)一個(gè)線程? 兩種方法

JDK中提供了一個(gè)Thread類,它可以幫助我們?cè)趈ava程序中額外啟動(dòng)一個(gè)線程。為什么說(shuō)是額外?因?yàn)閙ain函數(shù)也是一個(gè)線程,它稱之為程序的主線程。

啟動(dòng)一個(gè)線程,當(dāng)然就需要?jiǎng)?chuàng)建Thread類的一個(gè)實(shí)例:

Thread t = new Thread(){

@Override

publicvoid run() {

// TODO Auto-generated method stub

}

};

----------------------------------------------------------------

Thread t = new Thread(new Runnable(){

@Override

publicvoid run() {

// TODO Auto-generated method stub

}

});

t.start();

Thread類接收一個(gè)參數(shù),一個(gè)Runnable類型的對(duì)象,查看API文檔得知,Runnable是一個(gè)接口,并且定義了一個(gè)run()方法。

你只需要自定義一個(gè)類實(shí)現(xiàn)該接口,將你需要執(zhí)行的代碼,寫在run方法里就可以了。除此以外,開(kāi)啟線程還有另外一個(gè)辦法,那就是自定義一個(gè)類,繼承Thread類。再觀察API文檔,我們看到Thread類本身也實(shí)現(xiàn)了Runnable接口,所以我們把Thread類中的run方法進(jìn)行重寫,也可以達(dá)到目的。

線程的sleep()方法

線程的睡眠,睡眠時(shí)不占用CPU資源,可以被interrupt()方法打斷,打斷后線程會(huì)拋出InterruptedException,線程在睡眠的過(guò)程中,所拿到的同步鎖是不會(huì)釋放的。

線程的join()方法 (合并線程)

當(dāng)線程調(diào)用join方法時(shí),該線程會(huì)與當(dāng)前線程進(jìn)行合并,即等待該線程執(zhí)行完成,再繼續(xù)執(zhí)行,join還有帶參數(shù)的重載方法,可以指定等待多少毫秒。

若在main方法中執(zhí)行 t.join(2000);  main線程會(huì)等待線程t兩秒鐘,之后再運(yùn)行。

線程的yield()方法 (手動(dòng)切換線程 )

該方法使線程讓出CPU資源,由運(yùn)行狀態(tài)轉(zhuǎn)為就緒狀態(tài)。此時(shí)操作系統(tǒng)會(huì)重新為線程分配CPU。并且yield()方法只能讓同優(yōu)先級(jí)的線程有執(zhí)行的機(jī)會(huì)。

yield不會(huì)導(dǎo)致線程阻塞,所以無(wú)法保證一定能將CPU讓給別的線程。假設(shè)某個(gè)線程的優(yōu)先級(jí)別最高,此時(shí)調(diào)用yield方法,操作系統(tǒng)很有可能再次選中該線程并分配CPU。就好像一個(gè)年齡最大的人讓出自己最年長(zhǎng)的稱號(hào)讓大家重新選出最年長(zhǎng)者一樣。這種假惺惺的高風(fēng)亮節(jié)是不會(huì)獲得大家好感的。

線程的狀態(tài)和優(yōu)先級(jí)

線程的優(yōu)先級(jí)用數(shù)字來(lái)表示,從1~10表示優(yōu)先級(jí)由低到高。操作系統(tǒng)在調(diào)度CPU的時(shí)候,會(huì)優(yōu)先把CPU分配給優(yōu)先級(jí)高的線程來(lái)運(yùn)行。

線程的同步問(wèn)題

銀行取款,數(shù)據(jù)的并發(fā)操作

ATM
銀行柜臺(tái)
數(shù)據(jù)庫(kù)
查詢請(qǐng)求1
返回結(jié)果1
取款請(qǐng)求1
查詢請(qǐng)求2
返回結(jié)果2
取款請(qǐng)求2

查詢請(qǐng)求1和查詢請(qǐng)求2都執(zhí)行完畢的時(shí)候,假如數(shù)據(jù)庫(kù)返回的結(jié)果1和結(jié)果2都是余額為10000。此時(shí)銀行柜臺(tái)發(fā)出取款請(qǐng)求1,取款8000元,由于余額10000>8000,因此請(qǐng)求被允許,余額應(yīng)剩余2000。取款請(qǐng)求最終轉(zhuǎn)換為DATABASE的更新操作,將余額更新為2000. 在同一時(shí)刻,ATM發(fā)出取款請(qǐng)求2,取款8000元,由于余額10000>8000,因此請(qǐng)求再次被允許,余額應(yīng)剩余2000。取款請(qǐng)求最終同樣轉(zhuǎn)換為數(shù)據(jù)庫(kù)更新操作,將余額更新為2000。這個(gè)時(shí)候就出現(xiàn)了一個(gè)嚴(yán)重的問(wèn)題,共取走了16000,數(shù)據(jù)庫(kù)卻還剩2000。

這是一個(gè)非常經(jīng)典的多線程引發(fā)的安全問(wèn)題,為了解決這個(gè)問(wèn)題,我們引入同步鎖的概念。

同步鎖的概念:所謂同步,指的是按步驟依次執(zhí)行。如果是同時(shí)執(zhí)行的操作,我們稱為異步或者叫并發(fā)。當(dāng)一個(gè)線程執(zhí)行請(qǐng)求時(shí),如果把數(shù)據(jù)庫(kù)的一行記錄鎖定,其它線程此時(shí)不能操作數(shù)據(jù)庫(kù),必須等待第一個(gè)線程結(jié)束。這樣就能避免同時(shí)操作一行記錄所帶來(lái)的問(wèn)題。

線程安全問(wèn)題:是指當(dāng)多個(gè)線程訪問(wèn)同一個(gè)數(shù)據(jù)時(shí),如果每個(gè)線程都對(duì)該數(shù)據(jù)做了修改,那么該數(shù)據(jù)的值就會(huì)變得難以確定。一個(gè)值不能確定的變量,有可能會(huì)引發(fā)整個(gè)系統(tǒng)產(chǎn)生災(zāi)難性的錯(cuò)誤,所以這是我們絕不希望看到的。因此,解決線程安全問(wèn)題,兩種辦法:

第一、如果一個(gè)類需要被多線程訪問(wèn),那么絕對(duì)不要添加任何成員變量,防止多線程共享一份數(shù)據(jù)而引發(fā)的數(shù)據(jù)混亂。

第二、采用線程同步來(lái)訪問(wèn)同一個(gè)數(shù)據(jù)。

JAVA為了解決線程安全問(wèn)題,也引入了同步鎖的機(jī)制: Synchronized關(guān)鍵字

JVM的規(guī)范中這樣寫道:

“在JVM中,每個(gè)對(duì)象和類在邏輯上都是和一個(gè)監(jiān)視器相關(guān)聯(lián)的”
“為了實(shí)現(xiàn)監(jiān)視器的排他性監(jiān)視能力,JVM為每一個(gè)對(duì)象和類都關(guān)聯(lián)一個(gè)鎖”

這個(gè)也叫互斥鎖,就說(shuō)指多個(gè)線程同時(shí)來(lái)獲取對(duì)象的鎖,監(jiān)視器負(fù)責(zé)監(jiān)管對(duì)象的鎖,一次只允許一個(gè)線程拿到鎖。采用這樣的方法,使得多個(gè)線程可以同步順序執(zhí)行。

Synchronized關(guān)鍵字的四種用法:

public synchronized void someMethod() {

//方法體

}

該方法被聲明為同步方法,也就是說(shuō)執(zhí)行該方法必須獲得當(dāng)前對(duì)象鎖

public synchronized static void someMethod() {

//方法體

}

該方法被聲明為同步方法,由于方法為靜態(tài)的,因此無(wú)法獲得當(dāng)前對(duì)象的鎖,所以這個(gè)方法獲得的是當(dāng)前類的class對(duì)象鎖,也就是說(shuō)執(zhí)行該方法必須先獲得這個(gè)類的class對(duì)象鎖

public static void someMethod() {

synchronized(SynTest.class){

//方法體

}

}

該方法包含同步代碼塊,也就是說(shuō)執(zhí)行syn語(yǔ)句塊的代碼前必須先獲得當(dāng)前類的class對(duì)象鎖。

public void someMethod() {

synchronized(this){

//方法體

}

}

該方法包含同步代碼塊,也就是說(shuō)執(zhí)行syn語(yǔ)句塊的代碼前必須先獲得當(dāng)前對(duì)象鎖

synchronized用于指定同步代碼塊,并且它只能鎖定對(duì)象,無(wú)法鎖定基本數(shù)據(jù)類型。

線程的死鎖

死鎖,既永遠(yuǎn)也解不開(kāi)的鎖。在程序開(kāi)發(fā)中我們應(yīng)極力避免這種問(wèn)題。

當(dāng)線程1鎖定了資源A,同時(shí)線程2鎖定了資源B,這是線程1必須拿到資源B的鎖,才能執(zhí)行結(jié)束,從而釋放資源A。而線程2必須拿到資源A,才能釋放資源B。

形成這樣的僵局,兩個(gè)線程就無(wú)法結(jié)束,造成死鎖。

關(guān)于死鎖的例子程序:

publicclass DeadLock {

publicstaticvoid main(String[] args) {

Thread t1 = new Thread(new DL(true));

Thread t2 = new Thread(new DL(false));

t1.start();   t2.start();

}

}

class DL implements Runnable {

static Object lockX = new Object();

static Object lockY = new Object();

booleanflag = true;

public DL(boolean flag) {

this.flag = flag;

}

@Override

publicvoid run() {

if(flag) {

synchronized(lockX) {

try {

Thread.sleep(2000);

catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(lockY) {//阻塞

System.out.println("執(zhí)行結(jié)束");

}

}

else {

synchronized(lockY) {

try {

Thread.sleep(2000);

catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(lockX) {

System.out.println("執(zhí)行結(jié)束");

}

}

}

}

}

到此,關(guān)于“怎么創(chuàng)建Thread類”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI