怎么創(chuàng)建Thread類

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

我們提供的服務有:網(wǎng)站設計、成都網(wǎng)站設計、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、義安ssl等。為上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的義安網(wǎng)站制作公司

線程的基本概念

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

線程(Thread)是進程的一個實體,是CPU調度和分派的基本單位。線程不能夠獨立執(zhí)行,必須依存在應用程序中,由應用程序提供多個線程執(zhí)行控制。

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

要理解多線程的概念,就要首先明白它所帶來的好處,假設沒有線程的概念存在,那么當一個應用程序在執(zhí)行時,如果需要多個分支程序能夠同時處理數(shù)據(jù),就需要再開啟一個進程,

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

線程之間的切換

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

如何啟動一個線程? 兩種方法

JDK中提供了一個Thread類,它可以幫助我們在java程序中額外啟動一個線程。為什么說是額外?因為main函數(shù)也是一個線程,它稱之為程序的主線程。

啟動一個線程,當然就需要創(chuàng)建Thread類的一個實例:

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類接收一個參數(shù),一個Runnable類型的對象,查看API文檔得知,Runnable是一個接口,并且定義了一個run()方法。

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

線程的sleep()方法

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

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

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

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

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

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

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

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

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

線程的同步問題

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

ATM
銀行柜臺
數(shù)據(jù)庫
查詢請求1
返回結果1
取款請求1
查詢請求2
返回結果2
取款請求2

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

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

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

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

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

第二、采用線程同步來訪問同一個數(shù)據(jù)。

JAVA為了解決線程安全問題,也引入了同步鎖的機制: Synchronized關鍵字

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

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

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

Synchronized關鍵字的四種用法:

public synchronized void someMethod() {

//方法體

}

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

public synchronized static void someMethod() {

//方法體

}

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

public static void someMethod() {

synchronized(SynTest.class){

//方法體

}

}

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

public void someMethod() {

synchronized(this){

//方法體

}

}

該方法包含同步代碼塊,也就是說執(zhí)行syn語句塊的代碼前必須先獲得當前對象鎖

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

線程的死鎖

死鎖,既永遠也解不開的鎖。在程序開發(fā)中我們應極力避免這種問題。

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

形成這樣的僵局,兩個線程就無法結束,造成死鎖。

關于死鎖的例子程序:

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í)行結束");

}

}

else {

synchronized(lockY) {

try {

Thread.sleep(2000);

catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(lockX) {

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

}

}

}

}

}

到此,關于“怎么創(chuàng)建Thread類”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

網(wǎng)頁標題:怎么創(chuàng)建Thread類
網(wǎng)址分享:http://muchs.cn/article22/iiodcc.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供微信公眾號、企業(yè)網(wǎng)站制作、營銷型網(wǎng)站建設、網(wǎng)站建設軟件開發(fā)、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設