1. 程式人生 > >java多線程初探

java多線程初探

www. 機會 yum 多線程 捕獲 動態分配 結果 線程 其他

背景介紹

多線程是java一個很重要的知識點,了解多線程首先我們要了解兩個基礎概念,進程和線程。

進程:一個具有一定獨立功能的程序關於某個數據集合的一次運行活動。簡單理解就是一段程序的執行過程。

簡單的來講進程的概念主要有兩點:第一,進程是一個實體。每一個進程都有它自己的地址空間,一般情況下,包括文本區域(text region)、數據區域(data region)和堆棧(stack region)。文本區域存儲處理器執行的代碼;數據區域存儲變量和進程執行期間使用的動態分配的內存;堆棧區域存儲著活動過程調用的指令和本地變量。第二,進程是一個“執行中的程序”。程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體,我們稱其為進程。

線程:單個進程中執行中每個任務就是一個線程。

線程沒有單獨的地址空間,但有自己的棧段,用來存放局部變量和臨時變量。一個進程的所有線程可以共享該進程的所有資源。

進程是操作系統分配資源的最小單元,線程是操作系統調度的最小單元。

相比於進程,線程的開銷小,切換的速度快,而且還共享地址空間,通信方便,為了提升系統效率,就可以使用多線程。

知識剖析

新建狀態:

使用 new 關鍵字和 Thread 類或其子類建立一個線程對象後,該線程對象就處於新建狀態。它保持這個狀態直到程序 start() 這個線程。

就緒狀態:

當線程對象調用了start()方法之後,該線程就進入就緒狀態。就緒狀態的線程處於就緒隊列中,要等待JVM裏線程調度器的調度。

運行狀態:

如果就緒狀態的線程獲取 CPU 資源,就可以執行 run(),此時線程便處於運行狀態。處於運行狀態的線程最為復雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。

阻塞狀態:

如果一個線程執行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之後,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或獲得設備資源後可以重新進入就緒狀態。可以分為三種:

等待阻塞:運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。

同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)。

其他阻塞:通過調用線程的 sleep() 或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 狀態超時,join() 等待線程終止或超時,或者I/O 處理完畢,線程重新轉入就緒狀態。

死亡狀態:

一個運行狀態的線程完成任務或者其他終止條件發生時,該線程就切換到終止狀態。

常見問題

Java實現多線程的三種方法。

擴展思考

線程調度方法

線程的優先級

Thread類的setPriority()和getPriority()方法分別用來設置和獲取線程的優先級。

線程睡眠:Thread.sleep(long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒為單位。當睡眠結束後,就轉為就緒狀態。

線程讓步:Thread.yield() 方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。

yield()實際上只是讓當前運行線程回到就緒狀態,以允許具有相同優先級的其他線程獲得運行機會。因此,使用yield()的目的是讓相同優先級的線程之間能適當的輪轉執行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調度程序再次選中。

線程加入:join()方法,等待其他線程終止。在當前線程中調用另一個線程的join()方法,則當前線程轉入阻塞狀態,直到另一個進程運行結束,當前線程再由阻塞轉為就緒狀態。

線程等待:Object類中的wait()方法,導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 喚醒方法。

線程喚醒:Object類中的notify()方法,喚醒在此對象監視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,並在對實現做出決定時發生。線程通過調用其中一個 wait 方法,在對象的監視器上等待。 直到當前的線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。被喚醒的線程將以常規方式與在該對象上主動同步的其他所有線程進行競爭;類似的方法還有一個notifyAll(),喚醒在此對象監視器上等待的所有線程。

interrupt():只是拋出中斷異常,但如果捕獲該異常,線程不會直接中斷。

參考文獻

https://www.cnblogs.com/yjd_hycf_space/p/7526608.html

https://www.cnblogs.com/lwbqqyumidi/p/3804883.html

更多討論

Q1:start()方法和run()方法的區別

A1:只有調用了start()方法,才會表現出多線程的特性,不同線程的run()方法裏面的代碼交替執行。如果只是調用run()方法,那麽代碼還是同步執行的,必須等待一個線程的run()方法裏面的代碼全部執行完畢之後,另外一個線程才可以執行其run()方法裏面的代碼。

Q2:Runnable接口和Callable接口的區別

A2:Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執行run()方法中的代碼而已;Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果。

Q3:什麽是多線程的上下文切換

A3:多線程的上下文切換是指CPU控制權由一個已經正在運行的線程切換到另外一個就緒並等待獲取CPU執行權的線程的過程。

java多線程初探