麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

Java多線程開發系列之四:玩轉多線程(線程的控制2)

2019-11-14 23:07:00
字體:
來源:轉載
供稿:網友
java多線程開發系列之四:玩轉多線程(線程的控制2)

   在上節的線程控制(詳情點擊這里)中,我們講解了線程的等待join()、守護線程。本節我們將會把剩下的線程控制內容一并講完,主要內容有線程的睡眠、讓步、優先級、掛起和恢復、停止等。

  廢話不多說,我們直接進入正題:


3、線程睡眠 sleep()

  所有介紹多線程開發的學習案例中,基本都有用到這個方法,這個方法的意思就是睡眠(是真的,請相信我...)。好吧,如果你覺得不夠具體,可以認為是讓當前線程暫停一下,當前線程隨之進入阻塞狀態,當睡眠時間結束后,當前線程重新進入就緒狀態,開始新一輪的搶占計劃!

那么這個方法在實際開發中,有哪些用途呢?我舉個例子,很多情況下,當前線程并不需要實時的監控或者是運行,只是會定期的檢查一下某個狀態是否達標,如果符合出發條件了,那么就做某一件事情,否則繼續睡眠。比如心跳模式下,我們會派一個守護線程向服務端發送數據請求,當收到回應時,那么我們會睡眠一段時間,當再次蘇醒后,我們繼續發送這樣的請求。現實生活中的例子,比如我們在等某個電視是否開播,可是又不想看之前的廣告,所以我們可能會等一會將電視頻道切換到要播放的位置查看一下,如果還在播放廣告,那么我們就跳到其他頻道觀看,然后定期的切換到目標頻道進行查看一下。

代碼如下:

 1     public class ThreadStudy 2     { 3         public static main(String[] arg)throws Exception 4         { 5             for(int i=0;i<=1000;i++) 6             { 7                 if(IsInternetaccess()) 8                 { 9                     Thread.sleep(1000*6);//注意這里10                 }11                 else12                 {13                     System.out.

  代碼的意思是檢查網絡是否通暢,如果通暢的話那么進入睡眠,睡眠6秒鐘后再次蘇醒進行一次檢查。通過讓線程睡眠,我們可以有效的分配資源,在閑時讓其他線程可以更快的拿到cpu資源。這里有一點需要注意的是,線程睡眠后,進入阻塞狀態(無論此時cpu是否空閑,都仍然會暫停,是強制性的),當睡眠時間結束,進入的是就緒狀態,需要再次競爭才可以搶占到cpu權限,而非睡眠結束后立即可以執行方法。所以實際間隔時間是大于等于睡眠時間的。

java Thread類提供了兩個靜態方法來暫停線程

1  static void sleep(long millis)  2 3  static void sleep(long millis,int nanos)

  millis為毫秒,nanos為微秒,與線程join()類似,由于jvm和硬件的緣故,我們也基本只用方法1。


4、線程讓步 yield()

在生活中我們都遇到過這樣的例子,在公交車、地鐵上作一名安靜的美男子(或者是女漢子),這時候進來了一位老人、孕婦等,你默默的站起來,將座位讓給了老人。自己去旁邊候著,等著新的空閑座位。或者是你默默的玩著電腦游戲,然后你媽媽大聲的喊你的全名(是的,是全名),這時候你第一反應是,我又做錯什么了,第二反應就是放下手上的鼠標,乖乖的跑到你老媽面前接受訓斥。所有的這一切都是由于事情的緊急性當前正在處理的線程被擱置起來,我們(cpu)處理當前的緊急事務。在軟件開發中,也有類似的場景,比如一條線程處理的任務過大,其他線程始終無法搶占到資源,這時候我們就要主動的進行讓步,給其他線程一個公平搶占的機會。

這里附加一份來自網絡的圖片:在我們強大的時候,我們應該給弱者一個機會。咳咳 回歸正題。

下面是代碼

 1 public class TestThread extends Thead 2 { 3     public testThread(String name) 4     { 5         super(name); 6     } 7      8     public void run() 9     {10         for(int i=0;i<=1000000;ii++)11         {12             send("MsgBody");13             if(i%100==0)14             {15                 Thread.yield();//注意看這里16             }17         }18     }19     20     public static void main(String[] args) throws Exception21     {22         TestThread thread1=new TestThread("thread1");23         thread1.setPriority(Thread.MAX_PRIORITY);//注意看這里24         25         TestThread thread2=new TestThread("thread2");26         thread1.setPriority(Thread.MIN_PRIORITY);//注意看這里27         thread1.start();28         thread2.start();29     }30 }

我們啟動線程后,當線程每發送一百次消息后,我們暫停一次當前線程,使當前線程進入就緒狀態。此時CPU會重新計算一次優先級,選擇優先級較高者啟動。此處比較一下 sleep方法和yield()方法。

(1)sleep方法 暫停線程后,線程會進入阻塞狀態(即使是一瞬間),那么在這一刻cpu只會選擇已經做好就緒狀態的線程,故不會選擇當前正在睡眠的線程。(即使沒有其他可用線程)。而yield()方法會使當前線程即刻起進入就緒狀態,cpu選擇的可選線程范圍中,包含當前執行yield()方法的線程。如若沒有其他線程的優先級高于(或者等于) yield()的線程,則cpu仍會選擇原有yield()的線程重新啟動。

(2)sleep方法會拋出 InterruptedException 異常,所以調用sleep方法需要聲明或捕捉該異常(比C#處理異常而言是夠麻煩的),而yield沒有聲明拋出異常。

(3)sleep方法的移植性較好,可以對應很多平臺的底層方法,所以用sleep()的地方要多余yield()的地方;

(4)sleep 暫停線程后,線程會睡眠 一定時間,然后才會變為就緒狀態,倘若定義為sleep(0)后,則阻塞狀態的時間為0,即刻進入就緒狀態,這種用法與yield()的用法基本上是相同的:即都是讓cpu進行一次新的選擇,避免由于當前線程過度的霸占cpu,造成程序假死。

這兩個方法最大的不同點是 sleep會拋出異常需要處理,yield()不會; 而且兩者的微小區別在各個版本的jdk中也不一樣,大家看以參閱stackoverflow上的這個問題:Are Thread.sleep(0) and Thread.yield() statements equivalent?(點此進入)


5、線程的優先級設定

  線程的優先級相當于是一個機會的權重,優先級高時,獲得執行機會的可能性就越大,反之獲得執行機會的可能性就越小。(記住只是可能性越大或越小)。

  在本節的線程讓步這一部分的代碼里我們已經用代碼展示了如何設置線程的優先級此處不做特別的代碼展示。(防盜連接:本文首發自http://www.companysz.com/jilodream/ )

Thread為我們提供了兩個方法來分別設置和獲取線程的優先級。

  

1 setPriority(int newPriority)2 getPriority()

setPriority為設置優先級,參數的取值范圍是 1~10之前。

同時還設定了三個靜態常量:Tread.MAX_PRIORITY=10;

Tread.NORM_PRIORITY=5;

Tread.MIN_PRIORITY=1;

  盡管java為線程提供了10個優先級,但是底層平臺線程的優先級往往并不為10,所以就導致了兩者不是意義對應的關系。(比如OS只有五個優先級,這樣每兩個優先級只對應一個OS的優先級)。 此時我們常常只用這三個靜態常量來設置優先級,而不是詳細的指明具體的優先級值(因為可能多個優先級對應OS的某一個優先級),造成不必要的麻煩。

  另外每個線程默認的優先級都與創建他的父進程的優先級相同,在默認情況下Main線程優先級為普通,所以上述代碼創建的新線程默認也為普通優先級。

  下面是優先級概念的重點:

  其實你設置的優先級并不能真正代表該線程的或者啟動的優先級,這只是OS啟動線程時計算優先級的一個參考指標。OS還會查看當前線程是否長時間的霸占cpu,如果是這樣的話,OS會適度的調高對其它“饑餓”線程的優先級。對于那些長期霸占cpu的線程進行強制的掛起。進行這種設置只是能在某種程度上增加該線程被執行的機會。其實那些長期霸占cpu的線程也并非單次霸占的時間長,而是被連續選中的情況非常多,造成一種長期霸占的假象。

  所以設置優先級后,線程真正執行的順序并不可以預測甚至可以說是有點混亂的。在明白了這點以后,我們在開發控制多線程,并不能完全的寄希望于通過簡單的設置優先級來安排線程的執行順序。

此處參考了兩篇文章,更多詳情請參考原文:

(1)Java多線程 -- 線程的優先級(原文鏈接)

(2)Thread.sleep(0)的意義(原文鏈接)


6、強制結束線程Stop()

有時我們會發現有些正在運行的線程,已經沒有必要繼續執行下去了,但是距離多線程結束還有一段時間,這時我們就需要強制結束多線程。java曾經提供過一個專門用于結束線程的方法Stop(),但是這個方法現在已經被廢棄掉了,并不推薦開發者使用。

  這是由于這個方法具有固有的不安全性。用Thread.stop 來結束線程,jvm會強制釋放它鎖定的所有對象。當某一時刻對象的狀態并不一致時(正在處理事務的過程中),如果強制釋放掉對象,則可能會導致很多意想不到的后果。說的具體一點就是:系統會以被鎖定資源的棧頂產生一個ThreadDeath異常。這個unchecked Exception 會默默的關閉掉相關的線程。此時對象內部的數據可能會不一致,而用戶并不會收到任何對象不一致的報警。這個不一致的后果只會在未來使用過程中才會被發現,此時已經造成了無法預料的后果。

  有些人可能會考慮通過調用Stop方法,然后再捕捉ThreadDeath的形式,避免這種形式。這種想法看似可以實現,其實由于ThreadDeath這個異常可能在任何位置拋出,需要及細致的考慮。而且即使考慮到了,在捕捉處理該異常時,系統可能又會拋出新的ThreadDeath。所以我們應該在源頭上就扼殺掉這種方式,而不是通過不斷的打補丁來修復。

那么問題來了,如果我們真的要關閉掉某個線程,應該怎么處理呢?

通過Stop方法的講解我們可以明白,在線程的外部來關閉線程往往很難處理好數據一致性、以及線程內部運行過程的問題。那么我們可以通過設定一直標志變量,然后線程定期的檢查這個變量是否為結束標識來確定是否繼續運行。

例如筆者曾經寫過一個監控計算機指標的線程。這個線程會定期的檢查緩存中的狀態變量。這個狀態緩存是外部可以設定的。當線程發現此變量已經被設定為“結束”時,則會在內部處理好剩余工作,直接運行完Run方法。


7、線程的掛起和恢復 suspend()和resume()

我們有時需要對線程進行掛起,而具體掛起的時間并不清楚,只可能在未來某個條件下,通知這個線程可以開始工作了。java為我們專門提供了這樣的兩個方法:

掛起 suspend()/恢復resume。

通過標題我們已經知道這兩個方法也同樣不被java所推薦,但是為什么會這樣呢?

suspend是直接掛起當前線程,使其進入阻塞狀態,而對他內部控制和鎖定的資源并不進行修改(這與stop方法類似,線程外部往往很難查看內部運行的狀態和控制的資源,所以也就很難處理)。這樣這個被掛起的線程所鎖定的資源就再也不能被其他資源所訪問,造成了一種假死鎖的狀態。只有當線程被恢復(resume)后,并且釋放掉手里的資源,其他線程才可以重新訪問資源,但是倘若其他線程在恢復(resume)被掛起(suspend)的線程直線,需要先訪問被鎖定的資源,此時就會形成真正的鎖定。

那么問題來了,如果我們真的要掛起某個線程,應該怎么處理呢?

  這個與stop()同理,我們可以在可能被掛起的線程內部設置一個標識,指出這個線程當前是否要被掛起,若變量指示要掛起,則使用wait()命令讓其進入等待狀態,若標識指出可以恢復線程時,則用notify()重新喚醒這個線程。(這兩個方法我會在后文的線程通信中講解)。

此處參考了兩篇文章,更多詳情請參考原文:

(1)為何不贊成使用Thread.stopsuspend和resume()(原文鏈接)

  (2)JAVA STOP方法的不安全性(原文鏈接)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 久久精品国产一区二区电影 | 31freehdxxxx欧美| 56av国产精品久久久久久久 | 97久久日一线二线三线 | 91精品国产777在线观看 | 毛片在哪里看 | 污片视频网站 | 双性帝王调教跪撅打屁股 | 成年片在线观看 | 亚洲免费视频一区二区 | 久久精品re | 国产一区视频在线观看免费 | 91羞羞| 99pron| 精品国产一区二区亚洲人成毛片 | 中文字幕综合在线观看 | 国产资源视频在线观看 | 欧美视频一二区 | 视频久久免费 | 久久久久久久久成人 | 91av资源在线| 国产精品视频一区二区三区综合 | 国产成人精品无人区一区 | 91香草视频 | 亚洲免费视频大全 | 成人一区二区三区四区 | 国产永久免费观看 | 欧美日韩亚洲精品一区二区三区 | 特级a欧美做爰片毛片 | 亚洲天堂成人在线 | 乱淫67194| 日本中文字幕电影在线观看 | 亚洲婷婷日日综合婷婷噜噜噜 | 美女扒开腿让男生桶爽网站 | 欧美福利视频一区二区三区 | 深夜毛片免费看 | 黄色a级片视频 | 国产成人精品二区 | 日本在线观看视频网站 | 国产精品99久久久久久久女警 | 毛片网站网址 |