成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

@Java | Thread & synchronized - [ 多線程 基本使用]

zhunjiee / 481人閱讀

摘要:線程線程是進程中的一個實體,作為系統(tǒng)調度和分派的基本單位。下的線程看作輕量級進程。因此,使用的目的是讓相同優(yōu)先級的線程之間能適當?shù)妮嗈D執(zhí)行。需要注意的是,是線程自己從內部拋出的,并不是方法拋出的。

本文及后續(xù)相關文章梳理一下關于多線程和同步鎖的知識,平時只是應用層面的了解,由于最近面試總是問一些原理性的知識,雖說比較反感這種理論派,但是為了生計也必須掌握一番。(PS:并不是說掌握原理不好,但是封裝就是為了更好的應用,個人感覺沒必要為了學習而學習,比較傾向于行動派,能將原理應用到實際才算參透,本文也僅僅是背書而已)
知識點

進程:進程就是一段程序的執(zhí)行過程,指在系統(tǒng)中能獨立運行并作為資源分配的基本單位,它是由一組機器指令、數(shù)據(jù)和堆棧等組成的,是一個能獨立運行的活動實體。

線程:線程是進程中的一個實體,作為系統(tǒng)調度和分派的基本單位。Linux下的線程看作輕量級進程。

線程和進程一樣分為五個階段:創(chuàng)建、就緒、運行、阻塞、終止
多進程是指操作系統(tǒng)能同時運行多個任務(程序)
多線程是指在同一程序中有多個順序流在執(zhí)行
多線程使用說明 如何創(chuàng)建線程

實現(xiàn)Runnable接口

繼承Thread類

通過Callable和Future創(chuàng)建線程

1. 通過實現(xiàn)Runnable接口創(chuàng)建并運行線程

- 實現(xiàn)Runnable接口

Public class A implements Runnable {
    public void run () {    // 必須實現(xiàn)run方法
        // 線程執(zhí)行的業(yè)務代碼
    }
}
上面實現(xiàn)了Runnable接口并通過run方法包裝了需要通過線程執(zhí)行的代碼

- 運行線程
通過實現(xiàn)了Runnable接口的類的實例創(chuàng)建線程對象(Thread)來運行線程,常用的Thread構造方法:

Thread(Runnable threadOb,String threadName);
其中threadOb 是一個實現(xiàn)Runnable接口的類的實例threadName指定線程的名字

調用線程類中的start()方法運行線程 new Thread(threadOb,threadName).start();(可創(chuàng)建多個線程對象運行同一個Runnable接口實例的run方法,實現(xiàn)資源共享

PS:start()方法的調用后并不是立即執(zhí)行多線程代碼,而是使得該線程變?yōu)?b>可運行態(tài)(Runnable),等待CPU分配調度執(zhí)行
2. 繼承Thread類創(chuàng)建并運行線程

- 繼承Thread類

public class A extends Thread {
    @Override
    public void run() {    // 重寫run方法
        // 線程執(zhí)行的業(yè)務代碼
    }
}
上面繼承了Runnable接口并通過重寫run方法包裝了需要通過線程執(zhí)行的代碼,通過源碼可以看到Thread類也是實現(xiàn)了Runnable接口的,所以本質上和上一種方式無太大區(qū)別,不同的是Thread類不適合共享資源線程實現(xiàn)

- 運行線程

同樣是調用線程類中的start()方法運行線程,此時線程類為繼承Thread的類

3. 通過Callable和Future創(chuàng)建并運行線程

- 實現(xiàn)Callable接口

public class A implements Callable {
    @Override  
    public T call() throws Exception  // 實現(xiàn)call()方法
    {  
        //  線程執(zhí)行的業(yè)務代碼
    }  
}
創(chuàng)建Callable接口的實現(xiàn)類(通過泛型制定線程執(zhí)行結束后的返回值類型),并實現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值(返回值類型為Callable接口泛型制定的類型)

- 使用FutureTask類來包裝Callable對象

FutureTask ft = new FutureTask<>(callableObj);
其中callableObjCallable實現(xiàn)類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象call()方法的返回值

- 運行線程

通過FutureTask類的實例創(chuàng)建線程對象(Thread)來運行線程,此時應用的Thread`構造方法:

Thread(FutureTask futureObj,String threadName);
其中futureObj 是一個FutureTask 類的實例threadName指定線程的名字

調用線程類中的start()方法運行線程 new Thread(threadOb,threadName).start();
調用FutureTask對象的get()方法來獲得子線程執(zhí)行結束后的返回值

使用須知

多線程執(zhí)行的時候是無序的,即誰先獲取到CPU資源就可以先執(zhí)行,隨機性比較大

如果start()方法重復調用,會出現(xiàn)java.lang.IllegalThreadStateException異常

直接繼承Thread類和實現(xiàn)接口方式創(chuàng)建線程的區(qū)別

直接繼承Thread類方便快捷,適合相對單一無序的多線程執(zhí)行

實現(xiàn)接口方式適合多個相同的程序代碼的線程去處理同一個資源

實現(xiàn)接口方式可以避免java中的單繼承的限制

實現(xiàn)接口方式增加程序的健壯性,代碼可以被多個線程共享,代碼和數(shù)據(jù)獨立

線程池只能放入實現(xiàn)Runablecallable類線程,不能直接放入繼承Thread的類

Java程序運行首先會啟動一個JVM進程,然后至少啟動兩個線程,即main線程垃圾收集線程

Thread常用方法說明

sleep(long millis): 在指定的毫秒數(shù)內讓當前正在執(zhí)行的線程休眠(暫停執(zhí)行),可用TimeUnit.MILLISECONDS.sleep方法替換

join(): 等待調用join()的線程終止

使用方式

`Thread t = new AThread(); t.start(); t.join();`
join()的作用是將線程加入到當前線程中,只有執(zhí)行完join()調用線程才能執(zhí)行后面的代碼

使用場景
正常情況下主線程不依賴子線程執(zhí)行完成而結束,當主線程需要在子線程完成之后再結束時,可使用此方法

yield(): 暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程

使用說明
yield()只是將線程從運行狀態(tài)轉到可運行狀態(tài)(start()方法執(zhí)行后的狀態(tài)),不會導致線程轉到等待/睡眠/阻塞狀態(tài)

使用場景
yield()應該做的是讓當前運行線程回到可運行狀態(tài),以允許具有相同優(yōu)先級的其他線程獲得運行機會。因此,使用yield()的目的是讓相同優(yōu)先級的線程之間能適當?shù)妮嗈D執(zhí)行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調度程序再次選中

PS:yield()方法執(zhí)行時,當前線程仍處在可運行狀態(tài),所以,不可能讓出較低優(yōu)先級的線程些時獲得CPU占有權。在一個運行系統(tǒng)中,如果較高優(yōu)先級的線程沒有調用sleep方法,又沒有受到IO 阻塞,那么,較低優(yōu)先級線程只能等待所有較高優(yōu)先級的線程運行結束,才有機會運行

setPriority(): 更改線程的優(yōu)先級,優(yōu)先級高的線程會獲得較多的運行機會
優(yōu)先級靜態(tài)常量MIN_PRIORITY=1,NORM_PRIORITY=5,MAX_PRIORITY=10

使用方式

Thread t1 = new Thread("t1");
Thread t2 = new Thread("t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);

使用說明
Thread類的setPriority()和getPriority()方法分別用來設置和獲取線程的優(yōu)先級。
每個線程都有默認的優(yōu)先級。主線程的默認優(yōu)先級為Thread.NORM_PRIORITY。
線程的優(yōu)先級有繼承關系,比如A線程中創(chuàng)建了B線程,那么B將和A具有相同的優(yōu)先級。
JVM提供了10個線程優(yōu)先級,但與常見的操作系統(tǒng)都不能很好的映射。如果希望程序能移植到各個操作系統(tǒng)中,應該僅僅使用Thread類有以下三個靜態(tài)常量作為優(yōu)先級,這樣能保證同樣的優(yōu)先級采用了同樣的調度方式

interrupt(): 將線程對象的中斷標識設成true

使用說明

中斷只是一種協(xié)作機制,Java沒有給中斷增加任何語法,中斷的過程完全需要程序員自己實現(xiàn)。若要中斷一個線程,你需要手動調用該線程的interrupted方法,該方法也僅僅是將線程對象的中斷標識設成true;接著你需要自己寫代碼不斷地檢測當前線程的標識位;如果為true,表示別的線程要求這條線程中斷,此時究竟該做什么需要你自己寫代碼實現(xiàn)

每個線程對象中都有一個標識,用于表示線程是否被中斷;該標識位為true表示中斷,為false表示未中斷

通過調用線程對象的interrupt方法將該線程的標識位設為true;可以在別的線程中調用,也可以在自己的線程中調用

使用方式

在調用阻塞方法時正確處理InterruptedException異常

設置中斷監(jiān)聽(另一種方式)

Thread t1 = new Thread( new Runnable(){
       public void run(){
           // 若未發(fā)生中斷,就正常執(zhí)行任務
           while(!Thread.currentThread.isInterrupted()){
               // 正常任務代碼……
           }
   
           // 中斷的處理代碼……
           doSomething();
       }
   } ).start();

觸發(fā)中斷

t1.interrupt();

interrupt方法使用參考鏈接
大閑人柴毛毛

wait(): 主動釋放對象鎖,同時本線程休眠,直到有其它線程調用對象的notify()喚醒該線程,重新獲取對象鎖并執(zhí)行(wait()方法屬于Object中的方法,并不屬于Thread類)

notify(): 喚醒調用notify()對象的線程,notify()調用后,并不是馬上就釋放對象鎖的,而是在相應的synchronized(){}語句塊執(zhí)行結束,自動釋放鎖后,JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續(xù)執(zhí)行

Thread幾個方法比較

1.sleep()yield()的區(qū)別

sleep()使當前線程進入停滯狀態(tài),所以執(zhí)行sleep()的線程在指定的時間內肯定不會被執(zhí)行;yield()只是使當前線程重新回到可執(zhí)行狀態(tài),所以執(zhí)行yield()的線程有可能在進入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行

sleep方法使當前運行中的線程睡眼一段時間,進入不可運行狀態(tài),這段時間的長短是由程序設定的,yield方法使當前線程讓出CPU占有權,但讓出的時間是不可設定的。實際上,yield()方法對應了如下操作:先檢測當前是否有相同優(yōu)先級的線程處于同可運行狀態(tài),如有,則把CPU的占有權交給此線程,否則,繼續(xù)運行原來的線程。所以yield()方法稱為"退讓",它把運行機會讓給了同等優(yōu)先級的其他線程

sleep方法允許較低優(yōu)先級的線程獲得運行機會,但yield()方法執(zhí)行時,當前線程仍處在可運行狀態(tài),所以,不可能讓出較低優(yōu)先級的線程些時獲得CPU占有權。在一個運行系統(tǒng)中,如果較高優(yōu)先級的線程沒有調用 sleep方法,又沒有受到IO阻塞,那么,較低優(yōu)先級線程只能等待所有較高優(yōu)先級的線程運行結束,才有機會運行

2.wait()sleep()區(qū)別

共同點:

他們都是在多線程的環(huán)境下,都可以在程序的調用處阻塞指定的毫秒數(shù),并返回

wait()和sleep()都可以通過interrupt()方法 打斷線程的暫停狀態(tài),從而使線程立刻拋出InterruptedException

如果線程A希望立即結束線程B,則可以對線程B對應的Thread實例調用interrupt方法。如果此刻線程B正在wait/sleep /join,則線程B會立刻拋出InterruptedException,在catch() {} 中直接return即可安全地結束線程。

需要注意的是,InterruptedException是線程自己從內部拋出的,并不是interrupt()方法拋出的。對某一線程調用interrupt()時,如果該線程正在執(zhí)行普通的代碼,那么該線程根本就不會拋出InterruptedException。但是,一旦該線程進入到wait()/sleep()/join()后,就會立刻拋出InterruptedException

不同點:

sleep(),yield()等是Thread類的方法

wait()和notify()等是Object的方法

每個對象都有一個鎖來控制同步訪問。Synchronized關鍵字可以和對象的鎖交互,來實現(xiàn)線程的同步。sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法

wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用

簡單來說: 

sleep()睡眠時,保持對象鎖,仍然占有該鎖;

而wait()睡眠時,釋放對象鎖。

wait()和sleep()都可以通過interrupt()方法打斷線程的暫停狀態(tài),從而使線程立刻拋出InterruptedException(但不建議使用該方法)

sleep()方法

sleep()使當前線程進入停滯狀態(tài)(阻塞當前線程),讓出CPU的使用、目的是不讓當前線程獨自霸占該進程所獲的CPU資源,以留一定時間給其他線程執(zhí)行的機會;

sleep()是Thread類的Static的方法;因此他不能改變對象的機鎖,所以當在一個Synchronized塊中調用Sleep()方法是,線程雖然休眠了,但是對象的機鎖并沒有被釋放,其他線程無法訪問這個對象(即使休眠也持有對象鎖

在sleep()休眠時間期滿后,該線程不一定會立即執(zhí)行,這是因為其它線程可能正在運行而且沒有被調度為放棄執(zhí)行,除非此線程具有更高的優(yōu)先級

wait()方法

wait()方法是Object類里的方法;當一個線程執(zhí)行到wait()方法時,它就進入到一個和該對象相關的等待池中,同時失去(釋放)了對象的機鎖(暫時失去機鎖,wait(long timeout)超時時間到后還需要返還對象鎖);其他線程可以訪問;

wait()使用notify或者notifyAlll或者指定睡眠時間來喚醒當前等待池中的線程。

wait()必須放在synchronized block中,否則會在程序runtime時扔出java.lang.IllegalMonitorStateException異常。

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/69490.html

相關文章

  • @Java | Thread &amp; synchronized - [ 線程同步鎖 基本使用]

    摘要:線程同步方法是通過鎖來實現(xiàn),每個對象都有切僅有一個鎖,這個鎖與一個特定的對象關聯(lián),線程一旦獲取了對象鎖,其他訪問該對象的線程就無法再訪問該對象的其他非同步方法對于靜態(tài)同步方法,鎖是針對這個類的,鎖對象是該類的對象。 對實現(xiàn)了Runnable或者Callable接口類,可以通過多線程執(zhí)行同一實例的run或call方法,那么對于同一實例中的局部變量(非方法變量)就會有多個線程進行更改或讀取...

    Michael_Lin 評論0 收藏0
  • @Java | Thread &amp; synchronized - [ 線程 理論知識]

    摘要:死亡線程方法執(zhí)行結束,或者因異常退出了方法,則該線程結束生命周期。死亡的線程不可再次復生。直到當前的線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程。枚舉程序中的線程。強迫一個線程等待。通知一個線程繼續(xù)運行。 一. 線程狀態(tài)轉換圖 showImg(https://segmentfault.com/img/bV38ef?w=968&h=680); 線程間的狀態(tài)轉換說明: 新建(new)...

    harryhappy 評論0 收藏0
  • Java線程&amp;高并發(fā)

    摘要:線程啟動規(guī)則對象的方法先行發(fā)生于此線程的每一個動作。所以局部變量是不被多個線程所共享的,也就不會出現(xiàn)并發(fā)問題。通過獲取到數(shù)據(jù),放入當前線程處理完之后將當前線程中的信息移除。主線程必須在啟動其他線程后立即調用方法。 一、線程安全性 定義:當多個線程訪問某個類時,不管運行時環(huán)境采用何種調度方式,或者這些線程將如何交替執(zhí)行,并且在主調代碼中不需要任何額外的同步或協(xié)同,這個類都能表現(xiàn)出正確的行...

    SQC 評論0 收藏0
  • 深入理解 Java 線程系列(1)——一個簡單需求的并行改造 &amp; Java線程的通信問題

    摘要:所以接下來,我們需要簡單的介紹下多線程中的并發(fā)通信模型。比如中,以及各種鎖機制,均為了解決線程間公共狀態(tài)的串行訪問問題。 并發(fā)的學習門檻較高,相較單純的羅列并發(fā)編程 API 的枯燥被動學習方式,本系列文章試圖用一個簡單的栗子,一步步結合并發(fā)編程的相關知識分析舊有實現(xiàn)的不足,再實現(xiàn)邏輯進行分析改進,試圖展示例子背后的并發(fā)工具與實現(xiàn)原理。 本文是本系列的第一篇文章,提出了一個簡單的業(yè)務場景...

    ruicbAndroid 評論0 收藏0
  • Java線程基礎(一)——線程與鎖

    摘要:一線程的基本概念單線程簡單的說,單線程就是進程中只有一個線程。多線程由一個以上線程組成的程序稱為多線程程序。當線程調用完方法進入后會自動釋放鎖,線程獲得鎖。 一、線程的基本概念 1.1 單線程 簡單的說,單線程就是進程中只有一個線程。單線程在程序執(zhí)行時,所走的程序路徑按照連續(xù)順序排下來,前面的必須處理好,后面的才會執(zhí)行。 Java示例: public class SingleThrea...

    WelliJhon 評論0 收藏0

發(fā)表評論

0條評論

zhunjiee

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<