1. 程式人生 > >執行緒的生命週期以及控制執行緒

執行緒的生命週期以及控制執行緒

一、執行緒的生命週期

執行緒狀態轉換圖:


1、新建狀態

用new關鍵字和Thread類或其子類建立一個執行緒物件後,該執行緒物件就處於新生狀態。處於新生狀態的執行緒有自己的記憶體空間,通過呼叫start方法進入就緒狀態(runnable)。

注意:不能對已經啟動的執行緒再次呼叫start()方法,否則會出現java.lang.IllegalThreadStateException異常。

2、就緒狀態

處於就緒狀態的執行緒已經具備了執行條件,但還沒有分配到CPU,處於執行緒就緒佇列(儘管是採用佇列形式,事實上,把它稱為可執行池而不是可執行佇列。因為cpu的排程不一定是按照先進先出的順序來排程的),等待系統為其分配CPU。等待狀態並不是執行狀態,當系統選定一個等待執行的Thread物件後,它就會從等待執行狀態進入執行狀態,系統挑選的動作稱之為“cpu排程”。一旦獲得CPU,執行緒就進入執行狀態並自動呼叫自己的run方法。

提示:如果希望子執行緒呼叫start()方法後立即執行,可以使用Thread.sleep()方式使主執行緒睡眠一夥兒,轉去執行子執行緒。

3、執行狀態

處於執行狀態的執行緒最為複雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。

處於就緒狀態的執行緒,如果獲得了cpu的排程,就會從就緒狀態變為執行狀態,執行run()方法中的任務。如果該執行緒失去了cpu資源,就會又從執行狀態變為就緒狀態。重新等待系統分配資源。也可以對在執行狀態的執行緒呼叫yield()方法,它就會讓出cpu資源,再次變為就緒狀態。

當發生如下情況是,執行緒會從執行狀態變為阻塞狀態:

①、執行緒呼叫sleep方法主動放棄所佔用的系統資源

②、執行緒呼叫一個阻塞式IO方法,在該方法返回之前,該執行緒被阻塞

③、執行緒試圖獲得一個同步監視器,但更改同步監視器正被其他執行緒所持有

④、執行緒在等待某個通知(notify)

⑤、程式呼叫了執行緒的suspend方法將執行緒掛起。不過該方法容易導致死鎖,所以程式應該儘量避免使用該方法。

當執行緒的run()方法執行完,或者被強制性地終止,例如出現異常,或者呼叫了stop()、desyory()方法等等,就會從執行狀態轉變為死亡狀態。

4、阻塞狀態

處於執行狀態的執行緒在某些情況下,如執行了sleep(睡眠)方法,或等待I/O裝置等資源,將讓出

CPU並暫時停止自己的執行,進入阻塞狀態。 

在阻塞狀態的執行緒不能進入就緒佇列。只有當引起阻塞的原因消除時,如睡眠時間已到,或等待的I/O裝置空閒下來,執行緒便轉入就緒狀態,重新到就緒佇列中排隊等待,被系統選中後從原來停止的位置開始繼續執行。有三種方法可以暫停Threads執行:

5、死亡狀態

當執行緒的run()方法執行完,或者被強制性地終止,就認為它死去。這個執行緒物件也許是活的,但是,它已經不是一個單獨執行的執行緒。執行緒一旦死亡,就不能復生。 如果在一個死去的執行緒上呼叫start()方法,會丟擲java.lang.IllegalThreadStateException異常。

二、執行緒狀態的控制

Java提供了一些便捷的方法用於會執行緒狀態的控制。 .

 void
          已過時。 該方法最初用於破壞該執行緒,但不作任何清除。它所保持的任何監視器都會保持鎖定狀態。不過,該方法決不會被實現。即使要實現,它也極有可能以suspend() 方式被死鎖。如果目標執行緒被破壞時保持一個保護關鍵系統資源的鎖,則任何執行緒在任何時候都無法再次訪問該資源。如果另一個執行緒曾試圖鎖定該資源,則會出現死鎖。這類死鎖通常會證明它們自己是“凍結”的程序。有關更多資訊,請參閱為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?
 void join()
          等待該執行緒終止。
 void join(long millis)
          等待該執行緒終止的時間最長為 millis 毫秒。
 void join(long millis, int nanos)
          等待該執行緒終止的時間最長為 millis 毫秒 + nanos 納秒。
 void
          將該執行緒標記為守護執行緒或使用者執行緒。
 void
          更改執行緒的優先順序。
static void sleep(long millis)
          在指定的毫秒數內讓當前正在執行的執行緒休眠(暫停執行),此操作受到系統計時器和排程程式精度和準確性的影響。
static void sleep(long millis, int nanos)
          在指定的毫秒數加指定的納秒數內讓當前正在執行的執行緒休眠(暫停執行),此操作受到系統計時器和排程程式精度和準確性的影響。
 void start()
          使該執行緒開始執行;Java 虛擬機器呼叫該執行緒的 run 方法。
 void stop()
          已過時。 該方法具有固有的不安全性。用 Thread.stop 來終止執行緒將釋放它已經鎖定的所有監視器(作為沿堆疊向上傳播的未檢查ThreadDeath 異常的一個自然後果)。如果以前受這些監視器保護的任何物件都處於一種不一致的狀態,則損壞的物件將對其他執行緒可見,這有可能導致任意的行為。stop 的許多使用都應由只修改某些變數以指示目標執行緒應該停止執行的程式碼來取代。目標執行緒應定期檢查該變數,並且如果該變數指示它要停止執行,則從其執行方法依次返回。如果目標執行緒等待很長時間(例如基於一個條件變數),則應使用interrupt 方法來中斷該等待。有關更多資訊,請參閱為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?
 void
          已過時。 該方法具有固有的不安全性。有關詳細資訊,請參閱 stop()。該方法的附加危險是它可用於生成目標執行緒未準備處理的異常(包括若沒有該方法該執行緒不太可能丟擲的已檢查的異常)。有關更多資訊,請參閱為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?
 void
          已過時。 該方法已經遭到反對,因為它具有固有的死鎖傾向。如果目標執行緒掛起時在保護關鍵系統資源的監視器上保持有鎖,則在目標執行緒重新開始以前任何執行緒都不能訪問該資源。如果重新開始目標執行緒的執行緒想在呼叫resume 之前鎖定該監視器,則會發生死鎖。這類死鎖通常會證明自己是“凍結”的程序。有關更多資訊,請參閱為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?
static void yield()
          暫停當前正在執行的執行緒物件,並執行其他執行緒。

可以看到很多方法,已經標註為過時的,我們應該儘可能的避免使用它們,而應該重點關注start()、interrupt()、join()、sleep()、yield()等直接控制方法,和setDaemon()、setPriority()等間接控制方法。

1、執行緒睡眠——sleep

如果我們需要讓當前正在執行的執行緒暫停一段時間,並進入阻塞狀態,則可以通過呼叫Thread的sleep方法,從上面可以看到sleep方法有兩種過載的形式,但是使用方法一樣。

比如,我們想要使主執行緒每休眠100毫秒,然後再打印出數字:

  1. publicclass Test1 {  
  2.     publicstaticvoid main(String[] args) throws InterruptedException {  
  3.         for(int i=0;i<100;i++){  
  4.             System.out.println("main"+i);  
  5.             Thread.sleep(100);  
  6.         }  
  7.     }  
  8. }  
可以明顯看到列印的數字在時間上有些許的間隔。

注意如下幾點問題

①、sleep是靜態方法,最好不要用Thread的例項物件呼叫它,因為它睡眠的始終是當前正在執行的執行緒,而不是呼叫它的執行緒物件,它只對正在執行狀態的執行緒物件有效。看下面的例子:

  1. publicclass Test1 {  
  2.     publicstaticvoid main(String[] args) throws InterruptedException {  
  3.         System.out.println(Thread.currentThread().getName());  
  4.         MyThread myThread=new MyThread();  
  5.         myThread.start();  
  6.         myThread.sleep(1000);//這裡sleep的就是main執行緒,而非myThread執行緒
  7.         Thread.sleep(10);  
  8.         for(int i=0;i<100;i++){  
  9.             System.out.println("main"+i);  
  10.         }  
  11.     }  
  12. }  

②、Java執行緒排程是Java多執行緒的核心,只有良好的排程,才能充分發揮系統的效能,提高程式的執行效率。但是不管程式設計師怎麼編寫排程,只能最大限度的影響執行緒執行的次序,而不能做到精準控制。因為使用sleep方法之後,執行緒是進入阻塞狀態的,只有當睡眠的時間結束,才會重新進入到就緒狀態,而就緒狀態進入到執行狀態,是由系統控制的,我們不可能精準的去幹涉它,所以如果呼叫Thread.sleep(1000)使得執行緒睡眠1秒,可能結果會大於1秒。
  1. publicclass Test1 {  
  2.     publicstaticvoid main(String[] args) throws InterruptedException {  
  3.         new MyThread().start();  
  4.         new MyThread().start();  
  5.     }  
  6. }  
  7. class MyThread extends Thread {  
  8.     @Override
  9.     publicvoid run() {  
  10.         for (int i = 0; i < 3; i++) {  
  11.             System.out.println(this.getName()+"執行緒" + i + "次執行!");  
  12.             try {  
  13.                 Thread.sleep(50);  
  14.             } catch (InterruptedException e) {  
  15.                 e.printStackTrace();  
  16.             }  
  17.         }  
  18.     }  
  19. }  
看某一次的執行結果:
  1. Thread-0執行緒0次執行!  
  2. Thread-1執行緒0次執行!  
  3. Thread-1執行緒1次執行!  
  4. Thread-0執行緒1次執行!  
  5. Thread-0執行緒2次執行!  
  6. Thread-1執行緒2次執行!  
可以看到,執行緒0首先執行,然後執行緒1執行一次,又了執行一次。可以看到它並不是按照sleep的順序執行的。

2、執行緒讓步——yield

yield()方法和sleep()方法有點相似,它也是Thread類提供的一個靜態的方法,它也可以讓當前正在執行的執行緒暫停,讓出cpu資源給其他的執行緒。但是和sleep()方法不同的是,它不會進入到阻塞狀態,而是進入到就緒狀態。yield()方法只是讓當前執行緒暫停一下,重新進入就緒的執行緒池中,讓系統的執行緒排程器重新排程器重新排程一次,完全可能出現這樣的情況:當某個執行緒呼叫yield()方法之後,執行緒排程器又將其排程出來重新進入到執行狀態執行。

實際上,當某個執行緒呼叫了yield()方法暫停之後,優先順序與當前執行緒相同,或者優先順序比當前執行緒更高的就緒狀態的執行緒更有可能獲得執行的機會,當然,只是有可能,因為我們不可能精確的干涉cpu排程執行緒。

yield的用法:

  1. publicclass Test1 {  
  2.     publicstaticvoid main(String[] args) throws InterruptedException {  
  3.         new MyThread("低階"1).start();  
  4.         new MyThread("中級"5).start();  
  5.         new MyThread("高階"10).start();  
  6.     }  
  7. }  
  8. class MyThread extends Thread {  
  9.     public MyThread(String name, int pro) {  
  10.         super(name);// 設定執行緒的名稱
  11.         this.setPriority(pro);// 設定優先順序
  12.     }  
  13.     @Override
  14.     publicvoid run() {  
  15.         for (int i = 0; i < 30; i++) {  
  16.             System.out.println(this.getName() + "執行緒第" + i + "次執行!");  
  17.             

    相關推薦

    執行生命週期以及控制執行

    一、執行緒的生命週期 執行緒狀態轉換圖: 1、新建狀態 用new關鍵字和Thread類或其子類建立一個執行緒物件後,該執行緒物件就處於新生狀態。處於新生狀態的執行緒有自己的記憶體空間,通過呼叫start方法進入就緒狀態(runnabl

    Java之路:執行生命週期控制

    任何事物都有一個生命週期,執行緒也不例外。要想控制執行緒的生命,先得了解執行緒產生和消亡的整個過程。請讀者結合前面講的內容,請觀察下圖: 控制執行緒生命週期的方法有多種,如suspend()方法、resume()方法和stop()方法。但是這3個方法都不推薦使用,特別是suspend和

    Java併發程式設計之執行生命週期、守護執行、優先順序和join、sleep、yield

    Java併發程式設計中,其中一個難點是對執行緒生命週期的理解,和多種執行緒控制方法、執行緒溝通方法的靈活運用。這些方法和概念之間彼此聯絡緊密,共同構成了Java併發程式設計基石之一。 Java執行緒的生命週期 Java執行緒類定義了New、Runnable、Running Man、Blocked和Dead

    【2019春招準備:22.執行生命週期(主執行和子執行)】

    參考:強烈推薦 https://blog.csdn.net/u013905744/article/details/73741056 run java application: 建立一個java虛擬機器程序,main執行緒和userThread都可以在裡面跑,當沒有執行緒的時候,退出程

    執行生命週期以及五種基本狀態

    一.執行緒的生命週期及五種基本狀態 關於Java中執行緒的生命週期,首先看一下下面這張較為經典的圖: 上圖中基本上囊括了Java中多執行緒各重要知識點。掌握了上圖中的各知識點,Java中的多執行緒也就基本上掌握了。主要包括: Java執行緒具有五中基本狀態 新建狀態(New

    RunLoop六:在實際開發中的應用 之 控制執行生命週期執行保活) 二

    八、 停止 NSRunLoop 執行 上章提到了 ,只有控制器釋放了。執行緒沒有被釋放。這是因為 程式碼 卡在了 [[NSRunLoop currentRunLoop] run];這句程式碼. 任務執行完成後,執行緒會銷燬。但是 有 run 方法的話。代表系統一直在執行run

    RunLoop六:在實際開發中的應用 之 控制執行生命週期執行保活)

    一、前言 OC 的程式設計師大多數用過的 AFNetwork 這個網路請求框架。這個框架中就使用了 RunLoop 技術,去控制子執行緒的生命週期。 相當於 它建立了一個子執行緒,這個子執行緒會一直都在記憶體中,不會死亡。當某個時間段需要子執行緒工作時,會告訴子執行緒需要做什麼?過一段時間,

    執行Thread的生命週期以及狀態

          由於早上沒有網,所以幾篇寫好的部落格就一起發啦。       上2篇部落格中記錄了,執行緒和程序的異同,操作執行緒的常用方法的區別,其實,一個執行緒的生命週期在整個程序中是非常的重要的,它不僅僅關係到一個程序的效率,更能幫助我們靈活的使用執行緒。      

    java執行生命週期的圖示以及文字說明

    執行緒的生命週期,把圖轉化為文字就是: 執行緒通過new方法建立,呼叫start()方法,執行緒進入就緒狀態,等待系統的排程(時間片輪轉排程)。當系統排程,進入執行狀態。正常結束或者異常退出,程序進入死亡狀態。 處於執行狀態的執行緒若遇到sleep()

    Java多執行生命週期

    關於Java中執行緒的生命週期,首先看一下下面這張較為經典的圖: 上圖中基本上囊括了Java中多執行緒各重要知識點。掌握了上圖中的各知識點,Java中的多執行緒也就基本上掌握了。主要包括: Java執行緒具有五中基本狀態 新建狀態(New):當執行緒物件對建立後,即進入了

    執行生命週期你知道多少?

    xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003 百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!! 從之前的案例我們瞭解到多執行緒的作用優勢,這裡我們更詳細的瞭解執行緒的建立和結

    Thread、執行建立、synchronized、執行生命週期

    程序:程序指正在執行的程式,當一個程式進入記憶體執行,即變成一個程序,程序是處於執行過程中的程式,並且具有一定獨立功能。 執行緒:執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。 jvm啟動後,必然有一個執行路徑(執行緒)從main方法開始的,一直執行到main方法結束

    Java執行生命週期

    synchronized(waiting to enter monitor)等待獲得鎖 synchronized(enter monitor)獲得鎖 wait( ) join( ) LockSupport.park( ) notyfy( )、n

    Java 執行生命週期及五種狀態

    一、執行緒的生命週期 關於Java中執行緒的生命週期,如圖: 上圖中基本上包括了Java中多執行緒各重要知識點。掌握了上圖中的各知識點,Java中的多執行緒也就基本上掌握了。 主要包括: Java執行緒具有五中基本狀態 新建狀態(New):當執行緒物件對建立後,即進入了新建

    Python 執行,前臺執行,後臺執行生命週期

    import threading import time import win32api #引用系統函式 class Mythread(threading.Thread): #繼承threading.Thread def run(self): #run重寫,

    客觀面試題--8.執行生命週期是什麼?執行建立有幾種方式?

    1.執行緒的生命週期執行緒是一個動態執行的過程,它也有一個從產生到死亡的過程。(1)生命週期的五種狀態新建(new Thread)當建立Thread類的一個例項(物件)時,此執行緒進入新建狀態(未被啟動)。例如:Thread  t1=new Thread();就緒(runna

    java 執行生命週期

    執行緒的生命週期可以通過檢視Thread 的原始碼來看。 Thread這個類中有一個 State 的列舉類,其中定了了執行緒的6種狀態 public enum State { NEW, RUNNABLE,

    Python3-根據執行(Thread數量來檢視執行生命週期,第一種建立執行方法

    import threading,time,random#time就是時間戳1970, ''' 檢視執行緒數量,根據執行緒數量來檢視執行緒生命週期。執行緒之間是並行的,但是主執行緒是最後死亡。 ''' def sing(): for i in range(3):

    Java併發程式設計實戰(5)- 執行生命週期

    在這篇文章中,我們來聊一下執行緒的生命週期。 [toc] # 概述 執行緒是作業系統中的一個概念,在Java中,它是實現併發程式的主要手段。 Java中的執行緒,本質上就是作業系統中的執行緒。 作業系統中的執行緒有“生老病死”,專業說法就是生命週期,雖然不同的開發語言對於作業系統的執行緒做了不同的封裝

    python3 多執行 (threading) + 鎖 (Lock) + 控制執行數量 (Semaphore) 的例項

    學習記錄:python3 多執行緒 (threading ) + 鎖 (Lock) + 控制執行緒數量 (Semaphore) 的例項 import threading import time def sub(num): global count