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

資訊專欄INFORMATION COLUMN

多線程的創建和啟動

IT那活兒 / 763人閱讀
多線程的創建和啟動

點擊上方“IT那活兒”公眾號,關注后了解更多內容,不管IT什么活兒,干就完了!!!



多線程的創建和啟動

1. 多線程的實現原理

  • Java語言的JVM允許程序運行多個線程,多線程可以通過Java中的java.lang.Thread類來體現。
  • Thread類的特性。
每個線程都是通過某個特定的Thread對象的run()方法來完成操作,經常把run()方法的主體作為線程體。
通過Thread方法的start()方法來啟動這個線程,而非直接調用run()。

2. 多線程的創建

2.1 繼承Thread類

  • 創建一個繼承于Thread類的子類;
  • 重寫Thread類的run()方法;
  • 創建Thread類的子類的對象;
  • 通過此對象調用start()來啟動一個線程。
示例一--多線程執行同一段代碼:
示例二--多線程執行多段代碼:
示例三--創建Thread匿名子類:

2.2 實現Runnable接口

  • 創建一個實現Runnable接口的類;
  • 實現類去實現Runnable接口中的抽象方法:run();
  • 創建實現類的對象;
  • 將此對象作為參數傳到Thread類的構造器中,創建Thread類的對象;
  • 通過Thread類的對象調用start()方法。
示例:

2.3 兩種創建方式比較

  • Java中只允許單進程,以賣票程序TiketSales類來說,很有可能這個類本來就有父類,這樣一來就不可以繼承Thread類來完成多線程了,但是一個類可以實現多個接口,因此實現的方式沒有類的單繼承性的局限性,用實現Runnable接口的方式來完成多線程更加實用。
  • 實現Runnable接口的方式天然具有共享數據的特性(不用static變量)。
    因為繼承Thread的實現方式,需要創建多個子類的對象來進行多線程,如果子類中有變量A,而不使用static約束變量的話,每個子類的對象都會有自己獨立的變量A,只有static約束A后,子類的對象才共享變量A。
    而實現Runnable接口的方式,只需要創建一個實現類的對象,要將這個對象傳入Thread類并創建多個Thread類的對象來完成多線程,而這多個Thread類對象實際上就是調用一個實現類對象而已。實現的方式更適合來處理多個線程有共享數據的情況。
  • 聯系:Thread類中也實現了Runnable接口。
  • 相同點:兩種方式都需要重寫run()方法,線程的執行邏輯都在run()方法中。

2.4 通過實現Callable接口

與Runnable相比,Callable功能更加強大:
  • 相比run()方法,可以有返回值;

  • 方法可以拋出異常;
  • 支持泛型的返回值;
  • 需要借助FutureTask類,比如獲取返回結果。
示例:

2.5 通過線程池創建

1)背景
經常創建和銷毀、使用量特別大的資源,比如并發情況下的線程,對性能影響很大。
2)思路
提前創建好多個線程,放入線程池中,使用時直接獲取,使用完放回線程池中。可以避免頻繁的創建銷毀,實現重復利用。

3)優點

  • 提高響應速度(減少了創建新線程的時間);
  • 降低資源消耗(重復利用線程池中線程,不需要每次都創建);
  • 便于管理。
示例:



Thread類的常用方法

  • start():啟動當前線程, 調用當前線程的run()方法;
  • run() : 通常需要重寫Thread類中的此方法, 將創建的線程要執行的操作聲明在此方法中;
  • currentThread() : 靜態方法, 返回當前代碼執行的線程;
  • getName() : 獲取當前線程的名字;
  • setName() : 設置當前線程的名字;
  • yield() : 釋放當前CPU的執行權;
  • join() : 在線程a中調用線程b的join(), 此時線程a進入阻塞狀態, 知道線程b完全執行完以后, 線程a才結束阻塞狀態;
  • stop() : 已過時. 當執行此方法時,強制結束當前線程;
  • sleep(long militime) : 讓線程睡眠指定的毫秒數,在指定時間內,線程是阻塞狀態;
  • isAlive() :判斷當前線程是否存活。



線程的調度

1. CPU的調度策略

  • 時間片:cpu正常情況下的調度策略。即CPU分配給各個程序的時間,每個線程被分配一個時間段,稱作它的時間片,即該進程允許運行的時間,使各個程序從表面上看是同時進行的。

    如果在時間片結束時進程還在運行,則CPU將被剝奪并分配給另一個進程。如果進程在時間片結束前阻塞或結束,則CPU當即進行切換。而不會造成CPU資源浪費。

    在宏觀上:我們可以同時打開多個應用程序,每個程序并行不悖,同時運行。

    在微觀上:由于只有一個CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時間片,每個程序輪流執行。

  • 搶占式:高優先級的線程搶占cpu。

2. Java的調度算法

  • 同優先級線程組成先進先出隊列(先到先服務),使用時間片策略。
  • 堆高優先級,使用優先調度的搶占式策略。

1)線程的優先級等級(一共有10檔)

  • MAX_PRIORITY:10;

  • MIN_PRIORITY:1;

  • NORM_PRIORITY:5 (默認優先級)。

2)獲取和設置當前線程的優先級

  • getPriority()獲取;
  • setPriority(int p)設置。
說明:高優先級的線程要搶占低優先級線程cpu的執行權。但是只是從概率上講,高優先級的線程高概率的情況下被執行。并不意味著只有高優先級的線程執行完成以后,低優先級的線程才執行。



線程的生命周期

1. JDK中用Thread State類定義了線程的幾種狀態

  • 新建:當一個Thread類或其子類的對象被聲明并創建時,新的線程對象處于新建狀態。
  • 就緒:處于新建狀態的線程被start()后,將進入線程隊列等待CPU時間片,此時它已具備了運行的條件,只是沒分配到CPU資源。
  • 運行當就緒的線程被調度并獲得CPU資源時,便進入運行狀態,run()方法定義了線程的操作和功能。
  • 阻塞:在某種特殊情況下,被認為掛起或執行輸入輸出操作時,讓出CPU并臨時中止自己的執行,進入阻塞狀態。
  • 死亡:線程完成了它的全部工作或線程被提前強制性的中止或出現異常倒置導致結束。
2. 線程的生命周期流程圖



線程的同步

1. 多線程的安全性問題解析

1.1 線程的安全問題

  • 多個線程執行的不確定性引起執行結果的不穩定性;
  • 多個線程對賬本的共享, 會造成操作的不完整性, 會破壞數據;
  • 多個線程訪問共享的數據時可能存在安全性問題。
示例:
1.2 輸出結果
1.3 錯誤分析
當票數為1的時候,三個線程中有線程被阻塞沒有執行票數-1的操作,這是其它線程就會通過if語句的判斷,這樣一來就會造成多賣了一張票,出現錯票的情況。
極端情況為,當票數為1時,三個線程同時判斷通過,進入阻塞,然后多執行兩側賣票操作。
1.4 重票分析
如果t1在輸出票號22和票數-1的操作之間被阻塞,這就導致這時候t1賣出了22號票,但是總票數沒有減少。在t1被阻塞期間,如果t2運行到輸出票號時,那么t2也會輸出和t1相同的票號22。
通過以上兩種情況可以看出,線程的安全性問題時因為多個線程正在執行代碼的過程中,并且尚未完成的時候,其他線程參與進來執行代碼所導致的。

2. 多線程安全性問題解決

2.1 原理
當一個線程在操作共享數據的時候,其他線程不能參與進來。知道這個線程操作完共享數據的時候,其他線程才可以操作。即使當這個線程操作共享數據的時候發生了阻塞,依舊無法改變這種情況。
在Java中,我們通過同步機制,來解決線程的安全問題。
2.2 解決方式
1)同步代碼塊

synchronized(同步監視器){需要被同步的代碼塊}

  • 優點:同步的方式,解決了線程安全的問題。
  • 缺點:操作同步代碼時,只能有一個線程參與,與其他線程等待。相當于是一個單線程的過程,效率低。
2)同步方法
將所要同步的代碼放到一個方法中,將方法聲明為synchronized同步方法。之后可以在run()方法中調用同步方法。

要點:

  • 同步方法仍然涉及到同步監視器,只是不需要我們顯示的聲明。
  • 非靜態的同步方法,同步監視器是:this。
  • 靜態的同步方法,同步監視器是:當前類本身。
3)Lock鎖-JDK 5.0的新特性
JDK5.0之后,可以通過實例化ReentrantLock對象,在所需要同步的語句前,調用ReentrantLock對象的lock()方法,實現同步鎖,在同步語句結束時,調用unlock()方法結束同步鎖。
建議使用順序:Lock->同步代碼塊(已經進入了方法體,分配了相應的資源)->同步方法(在方法體之外)。

2.3 線程同步的死鎖問題

1)原理

  • 不同的線程分別占用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了死鎖。
  • 出現死鎖后,并不會出現異常,不會出現提示,只是所有的線程都處于阻塞狀態,無法繼續。
  • 使用同步時應避免出現死鎖。
2)Java中思索最簡單的情況
一個線程T1持有鎖L1并且申請獲得鎖L2,而另一個線程T2持有鎖L2并且申請獲得鎖L1,因為默認的鎖申請操作都是阻塞的,所以線程T1和T2永遠被阻塞了。導致了死鎖。這是最容易理解也是最簡單的死鎖的形式。但是實際環境中的死鎖往往比這個復雜的多。可能會有多個線程形成了一個死鎖的環路,比如:線程T1持有鎖L1并且申請獲得鎖L2,而線程T2持有鎖L2并且申請獲得鎖L3,而線程T3持有鎖L3并且申請獲得鎖L1,這樣導致了一個鎖依賴的環路:T1依賴T2的鎖L2,T2依賴T3的鎖L3,而T3依賴T1的鎖L1。從而導致了死鎖。
從上面的例子分析出原因:
線程在獲得一個鎖L1的情況下再去申請另外一個鎖L2,也就是鎖L1想要包含了鎖L2,也就是說在獲得了鎖L1,并且沒有釋放鎖L1的情況下,又去申請獲得鎖L2,這個是產生死鎖的最根本原因。另一個原因是默認的鎖申請操作是阻塞的。

3)死鎖的解決辦法

  • 專門的算法、原則。
  • 盡量減少同步資源的定義。
  • 盡量避免嵌套同步。
示例:



線程通信

很多情況下,盡管我們創建了多個線程,也會出現幾乎一個線程執行完所有操作的時候,這時候我們就需要讓線程間相互交流。

1. 原理
當一個線程執行完成其所應該執行的代碼后,手動讓這個線程進入阻塞狀態,這樣一來,接下來的操作只能由其他線程來操作。
當其他線程執行的開始階段,再手動讓已經阻塞的線程停止阻塞,進入就緒狀態,雖說這時候阻塞的線程停止了阻塞,但是由于現在正在運行的線程拿著同步鎖,所以停止阻塞的線程也無法立馬執行。
如此操作就可以完成線程間的通信。

2. 所用到的方法

  • wait():一旦執行此方法,當前線程就會進入阻塞,一旦執行wait()會釋放同步監視器。
  • notify():一旦執行此方法,將會喚醒被wait的一個線程。如果有多個線程被wait,就喚醒優先度最高的。
  • notifyAll() :一旦執行此方法,就會喚醒所有被wait的線程。
3. 說明
這三個方法必須在同步代碼塊或同步方法中使用。
三個方法的調用者必須是同步代碼塊或同步方法中的同步監視器。 
這三個方法并不時定義在Thread類中的,而是定義在Object類當中的。因為所有的對象都可以作為同步監視器,而這三個方法需要由同步監視器調用,所以任何一個類都要滿足,那么只能寫在Object類中。
4. sleep()和wait()的異同
相同點:兩個方法一旦執行,都可以讓線程進入阻塞狀態。

不同點:

  • 兩個方法聲明的位置不同:Thread類中聲明sleep(),Object類中聲明wait()。
  • 調用要求不同:sleep()可以在任何需要的場景下調用。wait()必須在同步代碼塊中調用。
  • 關于是否釋放同步監視器:如果兩個方法都使用在同步代碼塊呵呵同步方法中,sleep不會釋放鎖,wait會釋放鎖。
示例:


END




本文作者:趙畢皓(上海新炬王翦團隊)

本文來源:“IT那活兒”公眾號

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

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

相關文章

  • 什么是Java線程

    摘要:是不能直接調用系統功能的,所以,我們沒有辦法直接實現多線程程序。通過查看,我們知道了有種方式實現多線程程序。使用的是搶占式調度模型演示如何設置和獲取線程優先級返回線程對象的優先級更改線程的優先級線程默認優先級是。線程優先級的范圍是。 第五階段 多線程 前言: 一個場景:周末,帶著并不存在的女票去看電影,無論是現場買票也好,又或是手機買票也好,上一秒還有位置,遲鈍了一下以后,就顯示該座位...

    高璐 評論0 收藏0
  • Java 線程編程基礎——Thread 類

    摘要:程序執行時,至少會有一個線程在運行,這個運行的線程被稱為主線程。程序的終止是指除守護線程以外的線程全部終止。多線程程序由多個線程組成的程序稱為多線程程序。線程休眠期間可以被中斷,中斷將會拋出異常。 線程 我們在閱讀程序時,表面看來是在跟蹤程序的處理流程,實際上跟蹤的是線程的執行。 單線程程序 在單線程程序中,在某個時間點執行的處理只有一個。 Java 程序執行時,至少會有一個線程在運行...

    zhoutk 評論0 收藏0
  • Java 線程

    摘要:當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程所有運行中的任務通常對應一個進程。線程也被稱作輕量級進程,線程是進程的執行單元。在線程的生命周期中,它要經過新 線程概述 線程和進程 幾乎所有的操作系統都支持同時運行多個任務,一個任務通常就是一個程序,每個運行中的程序就是一個進程。當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程 所有運...

    zorro 評論0 收藏0
  • 大話javascript 4期:事件循環(1)

    摘要:腳本執行,事件處理等。引擎線程,也稱為內核,負責處理腳本程序,例如引擎。事件觸發線程,用來控制事件循環可以理解為,引擎線程自己都忙不過來,需要瀏覽器另開線程協助。異步請求線程,也就是發出請求后,接收響應檢測狀態變更等都是這個線程管理的。 一、進程與線程 現代操作系統比如Mac OS X,UNIX,Linux,Windows等,都是支持多任務的操作系統。 什么叫多任務呢?簡單地說,就是操...

    codergarden 評論0 收藏0
  • java 線程

    摘要:總結創建線程,方法運行線程。創建線程使用繼承類實現創建線程文檔該類必須重寫方法。為新線程的入口點。中斷線程它表示一個線程被中斷,會拋出錯誤。 java多線程 關于內存 每個線程會有自己的線程棧,即,變量不能共享,只能傳值拷貝每個線程new出的對象全都保存在堆中,全部共享 線程的生命周期 線程具有5種狀態,即新建,就緒,運行,阻塞,死亡。新建,當new出來一個線程以后,jvm為其分配內存...

    IamDLY 評論0 收藏0

發表評論

0條評論

IT那活兒

|高級講師

TA的文章

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