並發編程——認識java里的線程


本文系作者 chaoCode原創,轉載請私信並在文章開頭附帶作者和原文地址鏈接。

違者,作者保留追究權利。

前言

並發編程在我們日常開發中是時時刻刻都有在用的,只不過大部分的代碼底層已經幫我們去做了一些並發編程的安全處理,但是還是有很多情況下需要我們自己去控制,所以我們需要去了解學習並發編程,那么我們一步一步深入的開始學習。

認識java里的線程

Java 程序天生就是多線程的

一個 Java 程序從 main()方法開始執行,然后按照既定的代碼邏輯執行,看 似沒有其他線程參與,但實際上 Java 程序天生就是多線程程序,因為執行 main() 方法的是一個名稱為 main 的線程。

[6] Monitor Ctrl-Break //監控 Ctrl-Break 中斷信號的
[5] Attach Listener //內存 dump,線程 dump,類信息統計,獲取系統屬性等
[4] Signal Dispatcher // 分發處理發送給 JVM 信號的線程
[3] Finalizer // 調用對象 finalize 方法的線程
[2] Reference Handler//清除 Reference 的線程
[1] main //main 線程,用戶程序入口

Java線程的創建方式

Thread源碼有說明Java線程創建方式,一共有兩種。
1.繼承Thread類
2.實現Runable接口
當然網上也有人說有第三種,通過實現Callable和Future接口來創建線程。
在Thread類源碼中,給出了說明和線程創建方式示例:
image.png

image.png

Thread 才是 Java 里對線程的唯一抽象,Runable、Callable、Future 只是對任務(業務邏輯) 的抽象。
因此,出現了多種線程創建方式的說法。

1.繼承Thread

  • [1] 定義Thread類的子類,並重寫該類的run()方法,run()方法被稱為線程執行體。
  • [2] 創建Thread子類的實例,即創建線程對象。
  • [3] 調用線程對象的start()方法啟動該線程。
    image.png

2.實現Runnable接口
Thread提供一個帶參數的構造方法,我們通過實現Runnable接口再借用這個構造方法就可以獲取到根據我們自定義的任務的Thread對象

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

image.png

  • [1] 定義Runnable接口的實現類,並重寫該接口的run()方法。
  • [2] 創建Runnable實現類的實例,並以此實例作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。
  • [3] 調用線程對象的start()方法來啟動該線程。
    image.png

3.使用Callable和Future
實質也是使用Thread(Runnable target)構造方法,我們通過實現Callable接口實現一個帶返回值的任務,然后通過FutureTask類來包裝Callable對象,FutureTask這個類實現了RunnableFuture這個接口,但是RunnableFuture這個接口繼承了Runnable接口,所以就可以用這個構造方法就可以獲取到根據我們自定義的任務的Thread對象。
image.png
image.png
image.png

  • [1] 創建Callable接口的實現類,並實現call()方法,該call()方法作為線程執行體,且該call()方法有返回值。
  • [2] 創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該Future Task對象封裝了Callable對象的call()方法的返回值。
  • [3] 使用Future Task對象作為Thread對象的target創建線程對象。
  • [4] 調用線程對象的start()方法來啟動該線程。
  • [5] 調用Future Task對象的get()方法來獲得子線程執行結束后的返回值。

image.png

創建線程的三種方式對比

實現Runnable接口和實現Callable接口的方式基本相同,只是Callable接口里定義的方法有返回值,可以聲明拋出異常,大體上可以歸結為一大類。這種方式與繼承Thread方式之間的主要差別是采用實現Runnable,Callable接口創建多線程

1、線程類只是實現了Runnable接口或Callable接口,也可以繼續實現別的接口,還可以繼承其他類。
2、多個線程可以共享同一個Runnable對象,非常適合多個相同線程來處理同一份資源的情況(面向對象)。
3、如果要訪問當前線程,必須使用Thread.currentThread()方法,比較復雜。

采用繼承Thread類的方式創建線程:

1、因為線程類已經繼承了Thread類,所以不能再繼承其他父類。
2、如果要訪問當前線程,直接使用this即可獲得。

通過上面的分析我們發現創建線程的本質就如源碼所寫那樣有兩種方式。一個是繼承Thread類,一種是實現Runnable接口。

通過對比我們發現,通過接口去創建線程的方式會讓我們代碼有更大的容錯率,有更大的變通空間以及更加的靈活,同時也減少了程序之間的耦合度,畢竟六大原則中的依賴倒置原則的中心思想就是面向接口編程。所以推薦使用實現接口的方式來創建線程。

感謝諸君的觀看,文中如有紕漏,歡迎在評論區來交流。如果這篇文章幫助到了你,歡迎點贊👍關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM