那些年搞不懂的多執行緒、同步非同步及阻塞和非阻塞(一)---多執行緒簡介

木叔發表於2017-08-08

1、程式和執行緒的概念

程式:執行中的應用程式稱為程式,擁有系統資源(cpu、記憶體)

執行緒:程式中的一段程式碼,一個程式中可以有多段程式碼。本身不擁有資源(共享所在程式的資源);

在java中,程式入口被自動建立為主執行緒,在主執行緒中可以建立多個子執行緒。

區別:

 1、是否佔有資源問題

 2、建立或撤銷一個程式所需要的開銷比建立或撤銷一個執行緒所需要的開銷大。

 3、程式為重量級元件,執行緒為輕量級元件

 

多程式: 在作業系統中能同時執行多個任務(程式)

多執行緒: 在同一應用程式中有多個功能流同時執行

 

已經有了程式,為什麼還會需要執行緒呢?主要原因如下:

  1. 許多應用程式中,同時發生著多個活動。將這些應用程式分解成多個準並行的執行緒,程式設計的模型會變成更加簡單。
  2. 由於執行緒比程式進行更加輕量,建立和取消更加容易。
  3. 如果程式是IO密集型,那麼多執行緒執行能夠加快程式的執行速度。(如果是CPU密集型,則沒有這個優勢)
  4. 在多CPU系統中,多執行緒是可以真正並行執行的。

 

2、執行緒的主要特點

①、不能以一個檔名的方式獨立存在在磁碟中;

②、不能單獨執行,只有在程式啟動後才可啟動;

③、執行緒可以共享程式相同的記憶體(程式碼與資料)。

 

3、多執行緒原理

同一時間,CPU只能處理1條執行緒,只有1條執行緒在工作(執行)
多執行緒併發(同時)執行,其實是CPU快速地在多條執行緒之間排程(切換)
如果CPU排程執行緒的時間足夠快,就造成了多執行緒併發執行的假象

思考:如果執行緒非常非常多,會發生什麼情況?

CPU會在N多執行緒之間排程,CPU會累死,消耗大量的CPU資源

每條執行緒被排程執行的頻次會降低(執行緒的執行效率降低)

 

4、執行緒的主要用途

①、利用它可以完成重複性的工作(如實現動畫、聲音等的播放)。

②、從事一次性較費時的初始化工作(如網路連線、聲音資料檔案的載入)。

③、併發執行的執行效果(一個程式多個執行緒)以實現更復雜的功能

 

5、多執行緒(多個執行緒同時執行)程式的優缺點

優點:

①、可以減輕系統效能方面的瓶頸,因為可以並行操作;

②、提高CPU的處理器的效率,在多執行緒中,通過優先順序管理,可以使重要的程式優先操作,提高了任務管理的靈活性;

另一方面,在多CPU系統中,可以把不同的執行緒在不同的CPU中執行,真正做到同時處理多工。

缺點:

1、開啟執行緒需要佔用一定的記憶體空間(預設情況下,主執行緒佔用1M,子執行緒佔用512KB),如果開啟大量的執行緒,會佔用大量的記憶體空間,降低程式的效能

2、執行緒越多,CPU在排程執行緒上的開銷就越大

3、程式設計更加複雜:比如執行緒之間的通訊、多執行緒的資料共享

 

6、多執行緒的生命週期

執行緒狀態:

與人有生老病死一樣,執行緒也同樣要經歷新建、就緒、執行(活動)、阻塞和死亡五種不同的狀態。這五種狀態都可以通過Thread類中的方法進行控制。

 

建立並執行執行緒:

① 新建狀態(New Thread):在Java語言中使用new 操作符建立一個執行緒後,該執行緒僅僅是一個空物件,它具備類執行緒的一些特徵,但此時系統沒有為其分配資源,這時的執行緒處於建立狀態。

執行緒處於建立狀態時,可通過Thread類的方法來設定各種屬性,如執行緒的優先順序(setPriority)、執行緒名(setName)和執行緒的型別(setDaemon)等。

② 就緒狀態(Runnable):使用start()方法啟動一個執行緒後,系統為該執行緒分配了除CPU外的所需資源,使該執行緒處於就緒狀態。此外,如果某個執行緒執行了yield()方法,那麼該執行緒會被暫時剝奪CPU資源,重新進入就緒狀態。

③ 執行狀態(Running):Java執行系統通過排程選中一個處於就緒狀態的執行緒,使其佔有CPU並轉為執行狀態。此時,系統真正執行執行緒的run()方法。

a)     可以通過Thread類的isAlive方法來判斷執行緒是否處於就緒/執行狀態:當執行緒處於就緒/執行狀態時,isAlive返回true,當isAlive返回false時,可能執行緒處於阻塞狀態,也可能處於停止狀態。

④ 阻塞和喚醒執行緒

阻塞狀態(Blocked):一個正在執行的執行緒因某些原因不能繼續執行時,就進入阻塞 狀態。這些原因包括:

  • 等待阻塞:當執行緒執行了某個物件的wait()方法時,執行緒會被置入該物件的等待集中,直到執行了該物件的notify()方法wait()/notify()方法的執行要求執行緒首先獲得該物件的鎖。
  • 同步阻塞:當多個執行緒試圖進入某個同步區域(同步鎖)時,沒能進入該同步區域(同步鎖)的執行緒會被置入鎖定集(鎖池)中,直到獲得該同步區域的鎖,進入就緒狀態。
  • 其他阻塞:執行的執行緒執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。

⑤ 死亡狀態(Dead):執行緒在run()方法執行結束後進入死亡狀態。此外,如果執行緒執行了interrupt()或stop()方法,那麼它也會以異常退出的方式進入死亡狀態。

 

7、終止執行緒的三種方法

① 使用退出標誌,使執行緒正常退出,也就是當run方法完成後執行緒終止,推薦使用。

② 使用stop方法強制終止執行緒(這個方法不推薦使用,因為stop和suppend、resume一樣,也可能發生不可預料的結果)。

③ 使用interrupt方法中斷執行緒。

 

相關文章