面試官,Java多線程併發我能講3個小時,你確定要聽?

在讀本文之前,推薦大家先看一下霸哥之前的三篇文章:

關於Java核心面試知識點,已經講到了Java多線程併發,由於Java多線程併發內容較多,這章我將分為三篇文章來講,各位記得關注霸哥,上車不跟丟!

注:要獲取文章中高清完整思維導圖,以及PDF文件,後臺私信【Java】即可獲取免費領取方式!

故事小情節:

一個程序員去公司面試,本想穿著整齊,給面試官一個好印象,但沒想到被面試官瞧不起了...

面試官,Java多線程併發我能講3個小時,你確定要聽?

面試官:這位同志,我們這裡招Java高級工程師,你是不是走錯了?


程序員:沒有啊,我接到面試通知來的...


面試官:好吧,咱們這就開始吧!


程序員:好的


面試官:你之前做過哪些項目?


程序員:我一共主持開發過5個大型項目,若干個小項目,其中使我記憶最深刻的是...,當時我們運用了...技術,併發量提升了......


面試官:那你來講講Java中的多線程併發問題?


程序員:這個...


面試官:怎麼了?講不出來?我就知道...


程序員摘下帽子

面試官,Java多線程併發我能講3個小時,你確定要聽?

程序員:Java多線程併發我能講3個小時,你確定要聽?


面試官看著面前程序員鋥光發亮的腦門,眼中閃爍著無窮的光芒,聽到程序員這句胸有成竹的話,忙說:

面試官,Java多線程併發我能講3個小時,你確定要聽?

目錄

  • JAVA 併發知識庫
  • JAVA 線程實現/創建方式
  • 4 種線程池
  • 線程生命週期(狀態)
  • 終止線程 4 種方式
  • sleep 與 wait 區別
  • start 與 run 區別
  • JAVA 後臺線程
  • 線程基本方法

正文

面試官,Java多線程併發我能講3個小時,你確定要聽?

私信【Java】獲取高清完整大圖

JAVA 併發知識庫

面試官,Java多線程併發我能講3個小時,你確定要聽?

JAVA 線程實現/創建方式

1、繼承 Thread 類

Thread 類本質上是實現了 Runnable 接口的一個實例,代表一個線程的實例。啟動線程的唯一方法就是通過 Thread 類的 start()實例方法。start()方法是一個 native 方法,它將啟動一個新線程,並執行 run()方法。

<code>

public

class

MyThread

extends

Thread

{

public

void

run

()

{ System.out.println(

"MyThread.run()"

); } } MyThread myThread1 =

new

MyThread(); myThread1.start();/<code>

2、實現 Runnable 接口

如果自己的類已經 extends 另一個類,就無法直接 extends Thread,此時,可以實現一個Runnable 接口。

<code>

public

class

MyThread

extends

OtherClass

implements

Runnable

{

public

void

run

()

{ System.out.println(

"MyThread.run()"

); } } MyThread myThread =

new

MyThread(); Thread thread =

new

Thread(myThread); thread.start(); target.run()

public

void

run

()

{

if

(target !=

null

) { target.run(); } }/<code>

3、ExecutorService、Callable、Future 有返回值線程

有返回值的任務必須實現 Callable 接口,類似的,無返回值的任務必須 Runnable 接口。執行Callable 任務後,可以獲取一個 Future 的對象,在該對象上調用 get 就可以獲取到 Callable 任務返回的 Object 了,再結合線程池接口 ExecutorService 就可以實現傳說中有返回結果的多線程了。

<code> 
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
 
List 

list

=

new

ArrayList();

for

(

int

i =

0

; i < taskSize; i++) { Callable c =

new

MyCallable(i +

" "

); Future f = pool.submit(c);

list

.add(f); } pool.shutdown();

for

(Future f :

list

) { System.out.println(

"res:"

+ f.get().toString()); }/<code>

4、基於線程池的方式

線程和數據庫連接這些資源都是非常寶貴的資源。那麼每次需要的時候創建,不需要的時候銷燬,是非常浪費資源的。那麼我們就可以使用緩存的策略,也就是使用線程池。

<code> 
ExecutorService threadPool = Executors.newFixedThreadPool(

10

);

while

(

true

) { threadPool.execute(

new

Runnable() { @

Override

public

void

run

(

)

{ System.

out

.println(Thread.currentThread().getName() +

" is running .."

);

try

{ Thread.sleep(

3000

); }

catch

(InterruptedException e) { e.printStackTrace(); } } }); }/<code>

4 種線程池

面試官,Java多線程併發我能講3個小時,你確定要聽?

Java 裡面線程池的頂級接口是 Executor,但是嚴格意義上講 Executor 並不是一個線程池,而只是一個執行線程的工具。真正的線程池接口是 ExecutorService

面試官,Java多線程併發我能講3個小時,你確定要聽?

1、newCachedThreadPool

創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。對於執行很多短期異步任務的程序而言,這些線程池通常可提高程序性能。調用 execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長時間保持空閒的線程池不會使用任何資源。

2、newFixedThreadPool

創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態。如果在所有線程處於活動狀態時提交附加任務,則在有可用線程之前,附加任務將在隊列中等待。如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。在某個線程被顯式地關閉之前,池中的線程將一直存在。

3、newScheduledThreadPool

創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行。

<code>ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(

3

); scheduledThreadPool.schedule(newRunnable() { @

Override

public

void

run

(

)

{ System.

out

.println(

"延遲三秒"

); } },

3

, TimeUnit.SECONDS); scheduledThreadPool.scheduleAtFixedRate(newRunnable() { @

Override

public

void

run

(

)

{ System.

out

.println(

"延遲 1 秒後每三秒執行一次"

); } },

1

,

3

, TimeUnit.SECONDS);/<code>

4、newSingleThreadExecutor


Executors.newSingleThreadExecutor()返回一個線程池(這個線程池只有一個線程),這個線程池可以在線程死後(或發生異常時)重新啟動一個線程來替代原來的線程繼續執行下去!

為了避免文章篇幅過長,下面的章節就簡單介紹,不一一將小節內容發出來了!需要的話可以後臺私信【Java】免費領取PDF文檔!

線程生命週期(狀態)

當線程被創建並啟動以後,它既不是一啟動就進入了執行狀態,也不是一直處於執行狀態。在線程的生命週期中,它要經過新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5 種狀態。尤其是當線程啟動以後,它不可能一直"霸佔"著 CPU 獨自運行,所以 CPU 需要在多條線程之間切換,於是線程狀態也會多次在運行、阻塞之間切換。

面試官,Java多線程併發我能講3個小時,你確定要聽?

終止線程 4 種方式

面試官,Java多線程併發我能講3個小時,你確定要聽?

sleep 與 wait 區別

1. 對於 sleep()方法,我們首先要知道該方法是屬於 Thread 類中的。而 wait()方法,則是屬於Object 類中的。


2. sleep()方法導致了程序暫停執行指定的時間,讓出 cpu 該其他線程,但是他的監控狀態依然保持著,當指定的時間到了又會自動恢復運行狀態。


3. 在調用 sleep()方法的過程中,線程不會釋放對象鎖。


4. 而當調用 wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用 notify()方法後本線程才進入對象鎖定池準備獲取對象鎖進入運行狀態。

start 與 run 區別

1. start()方法來啟動線程,真正實現了多線程運行。這時無需等待 run 方法體代碼執行完畢,可以直接繼續執行下面的代碼。


2. 通過調用 Thread 類的 start()方法來啟動一個線程, 這時此線程是處於就緒狀態, 並沒有運行。


3. 方法 run()稱為線程體,它包含了要執行的這個線程的內容,線程就進入了運行狀態,開始運行 run 函數當中的代碼。 Run 方法運行結束, 此線程終止。然後 CPU 再調度其它線程。

JAVA 後臺線程

守護線程--也稱“服務線程”,他是後臺線程,它有一個特性,即為用戶線程提供公共服務,在沒有用戶線程可服務時會自動離開。

面試官,Java多線程併發我能講3個小時,你確定要聽?

線程基本方法

線程相關的基本方法有 wait,notify,notifyAll,sleep,join,yield 等。

面試官,Java多線程併發我能講3個小時,你確定要聽?

看完了記得收藏和轉發,然後私信【Java】哦~

針對於Java程序員,我這邊還準備免費的Java架構學習資料(裡面有高可用、高併發、高性能及分佈式、Jvm性能調優、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)

學習視頻和麵試PDF都是可以免費分享的,希望能夠幫助到有需要的朋友,同時也節省了大家再去網上找資料的時間。

面試官,Java多線程併發我能講3個小時,你確定要聽?

下面霸哥將繼續分享Java多線程編髮:Java鎖、上下文切換、線程池原理等,關注我上車別跟丟!


分享到:


相關文章: