java多執行緒初探
這裡是修真院後端小課堂,每篇分享文從
【背景介紹】【知識剖析】【常見問題】【解決方案】【編碼實戰】【擴充套件思考】【更多討論】【參考文獻】
八個方面深度解析後端知識/技能,本篇分享的是:
【java多執行緒初探】
大家好,我是IT修真院鄭州分院第十期的學員,一枚正直純潔善良的java程式設計師
今天給大家分享一下,修真院官網java任務十,深度思考中的知識點——java多執行緒初探。
背景介紹
多執行緒是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執行權的執行緒的過程。
更多內容,可以加入IT交流群565734203與大家一起討論交流
這裡是技能樹·IT修真院:http://www.jsnhu.com,初學者轉行到網際網路的聚集地