国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

zhunjiee / 478人閱讀

摘要:線程線程是進程中的一個實體,作為系統調度和分派的基本單位。下的線程看作輕量級進程。因此,使用的目的是讓相同優先級的線程之間能適當的輪轉執行。需要注意的是,是線程自己從內部拋出的,并不是方法拋出的。

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

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

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

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

實現Runnable接口

繼承Thread類

通過Callable和Future創建線程

1. 通過實現Runnable接口創建并運行線程

- 實現Runnable接口

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

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

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

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

PS:start()方法的調用后并不是立即執行多線程代碼,而是使得該線程變為可運行態(Runnable),等待CPU分配調度執行
2. 繼承Thread類創建并運行線程

- 繼承Thread類

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

- 運行線程

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

3. 通過Callable和Future創建并運行線程

- 實現Callable接口

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

- 使用FutureTask類來包裝Callable對象

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

- 運行線程

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

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

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

使用須知

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

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

直接繼承Thread類和實現接口方式創建線程的區別

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

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

實現接口方式可以避免java中的單繼承的限制

實現接口方式增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立

線程池只能放入實現Runablecallable類線程,不能直接放入繼承Thread的類

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

Thread常用方法說明

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

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

使用方式

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

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

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

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

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

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

setPriority(): 更改線程的優先級,優先級高的線程會獲得較多的運行機會
優先級靜態常量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()方法分別用來設置和獲取線程的優先級。
每個線程都有默認的優先級。主線程的默認優先級為Thread.NORM_PRIORITY。
線程的優先級有繼承關系,比如A線程中創建了B線程,那么B將和A具有相同的優先級。
JVM提供了10個線程優先級,但與常見的操作系統都不能很好的映射。如果希望程序能移植到各個操作系統中,應該僅僅使用Thread類有以下三個靜態常量作為優先級,這樣能保證同樣的優先級采用了同樣的調度方式

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

使用說明

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

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

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

使用方式

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

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

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

觸發中斷

t1.interrupt();

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

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

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

Thread幾個方法比較

1.sleep()yield()的區別

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

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

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

2.wait()sleep()區別

共同點:

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

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

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

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

不同點:

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

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

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

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

簡單來說: 

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

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

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

sleep()方法

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

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

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

wait()方法

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

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

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

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

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

相關文章

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

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

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

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

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

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

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

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

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

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

    WelliJhon 評論0 收藏0

發表評論

0條評論

zhunjiee

|高級講師

TA的文章

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