目錄
一、行程與執行緒
1、行程是程式運行資源分配的最小單位
2、執行緒是CPU 調度的最小單位,必須依賴行程而存在
3、線程無所不在
二、CPU 核心數與執行緒數的關係
1、多核心
2、多執行緒
3、核心數、執行緒數
三、CPU 時間片輪轉機制
四、並行和並發
1、並發
2、並行
五、高並發程式設計
1、CPU 資源利用的充分
2、加快用戶回應時間
3、讓程式碼模組化、非同步化、簡化
六、多執行緒注意事項
1、執行緒之間的安全性
2、執行緒之間的死鎖
3、線程多了會將服務資源耗盡形成死機、當機
七、多執行緒注意事項
首頁 Java java教程 Java中的多執行緒共享變數與協作機制

Java中的多執行緒共享變數與協作機制

Apr 20, 2023 pm 03:55 PM
java

    一、行程與執行緒

    1、行程是程式運行資源分配的最小單位

    進程是作業系統進行資源分配的最小單位,其中包括:CPU、記憶體空間、磁碟IO 等、同一進程中的多條執行緒共享該進程中的全部系統資源,而進程和進程直接是相互獨立的。進程是具有一定獨立功能的程式關於某個資料集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。

    進程是程式在電腦上的一次執行活動。當你執行一個程序,你就啟動了一個進程。顯然程式是死的、靜態的、進程是活動的、動態的。進程可以分為系統進程和使用者進程。凡是用於完成作業系統的各種功能的進程就是系統進程,它們是處於運行狀態下的作業系統本身,使用者進程就是所有由你啟動的進程。

    2、執行緒是CPU 調度的最小單位,必須依賴行程而存在

    #執行緒是進程的一個實體,是CPU調度和分派的基本單位,它是比經常更小的、能夠獨立運作的基本單位。線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程式計數器,一組寄存器和堆疊),但是它可以與同一個進程的其他線程共享進程所擁有的全部資源。

    3、線程無所不在

    任何一個程式都必須建立線程,特別是Java不管任何程式都必須啟動一個main函數的主執行緒;Java web開發的定時任務、定時器、JSPServlet、非同步訊息處理機制,遠端存取介面RM 等,任何一個監聽事件,onClick的觸發事件等都離不開線程和並發的知識。

    二、CPU 核心數與執行緒數的關係

    1、多核心

    多核心:也指單晶片多處理器(Chip Multiprocessors,簡稱CMP),CMP是由美國史丹佛大學提出的,其思想是將大規模並行處理器中的SMP(對稱處理器)整合到同一晶片內,各個處理器並行執行不同的進程。這種依靠多個CPU同時並行的運行程序是實現超高速運算的一個重要方向,稱為平行處理。

    2、多執行緒

    多執行緒Simultaneous Multithreading.簡稱SMT.讓同一個處理器上的多個執行緒同步執行並共享處理器的執行資源。

    3、核心數、執行緒數

    核心數、執行緒數:目前主流CPU都是多核心的。增加核心數目的就是為了增加執行緒數,因為作業系統是透過執行緒來執行任務的,一般情況下它們是1:1對應關係,也就是說四核心CPU#一般擁有四個線程。但Intel引入超執行緒技術後,使核心數與執行緒數形成了1:2的關係。

    Java中的多執行緒共享變數與協作機制

    三、CPU 時間片輪轉機制

    我們平常在開發的時候,感覺並沒有受CPU 核心數的限制,想啟動執行緒就啟動線程,哪怕是在單核心CPU 上,為什麼?這是因為作業系統提供了一個CPU 時間片輪轉機制。

    時間片輪換調度是一種最古老、最簡單、最公平且使用最廣的演算法,又稱為RR 調度。每個行程被分配一個時間段,稱為它的時間片,也就是該行程運行運行的時間。

    四、並行和並發

    我們舉個例子,如果有高速公路A,上面有4條車道,那麼最大並行車輛就是4輛,這條高速公路同時並排行走的車輛小與等於4的時候,車輛就可以並行行駛。 CPU也是這個原理,一個CPU相當於一條高速公路,核心數或執行緒數就相當於並排可以通行的車輛;而多個CPU就相當於有多條高速公路,而每個高速公路並排多個車道。

    當談論並發的時候,一定要加個單位時間,也就是說單位時間內並發量是多少?離開單位時間其實是沒有意義的。

    俗話說一心不能二用,這對電腦也一樣,原則上一個CPU#只能分配給一個進程,以便運行這個進程。我們通常使用的電腦只有一個CPU,也就是說只有一顆心,要讓它一心多用同時運行多個進程,就必須使用並發技術。實現並發技術相當複雜,最容易理解的是「時間片輪轉進程調度演算法」。

    1、並發

    並發:指應用程式能夠交替執行不同的任務,例如單一CPU核心下執行多執行緒並非同時執行多個任何,如果你開兩個執行緒執行,就是在你幾乎不可察覺的速度不斷去切換執行這兩個任務,以達到「同時執行」效果,只是電腦的執行速度太快,我們無法察覺到而已。

    2、並行

    並行:指應用程式能夠同時執行不同的任務,例如:吃飯的時候可以邊吃邊看電視,這兩件事可以同時執行。

    **並發和並行兩者的差異就是:一個是交替執行,一個是同時執行**

    Java中的多執行緒共享變數與協作機制

    五、高並發程式設計

    由於多核心CPU的誕生,多執行緒、高並發的程式設計越來越受重視和關注。

    1、CPU 資源利用的充分

    從上面CPU的介紹,可以看出現在市面上沒有CPU的核心不使用多線程並發機制的,特別是伺服器還不只一個CPU。程式的基本調度單元是線程,一個線程也只能在一個一個CPU 的一個核的一個線程跑,如果你是個i3的CPU的話,最差也是雙核心4線程的運算能力:如果是線程的話,那就會浪費釣3/4的CPU效能:如果設計多執行緒的話,那它就可以同時在多個CPU 的多個核的多個執行緒上跑,可以充分的利用CPU,減少CPU的空閒時間,發揮它的運算能力,提高並發量。

    2、加快用戶回應時間

    例如我們經常使用的下載功能,很多朋友都會開通某一個會員,因為會員版本啟用了多個線程去下載,誰都無法忍受一個線程去下,為什麼呢?因為多執行緒下載快啊。

    我們做程式開發的時候,網頁速度提升1s,如果用戶量大的話,就能增加不少轉換量。我們常瀏覽的網頁中,瀏覽器在載入頁面的時候,都會去多開幾個執行緒去載入網路資源,提升網站的相應速度。 多執行緒和高並發,在電腦中,無所不在。

    3、讓程式碼模組化、非同步化、簡化

    例如我們做一個電商項目,下訂單和給用戶發送簡訊、郵件就可以進行拆分,將發送簡訊給用戶、郵件這兩個步驟獨立成兩個單獨的模組,交給其他執行緒去執行。這樣即增加了非同步的操作,提示了系統效能,又使程式模組化,清晰化和簡化。

    六、多執行緒注意事項

    1、執行緒之間的安全性

    在同一個行程裡面的多執行緒是資源共享的,也就是都可以訪問同一個記憶體位址當中的一個變數。

    例如:若每個執行緒中對全域變數、靜態變數只讀操作,而無寫操作,一般來說,這個全域變數是執行緒安全的;若有多個執行緒同時執行寫入操作,一般都需要考慮線程同步,否則就可能影響線程安全。

    2、執行緒之間的死鎖

    為了解決執行緒之間的安全性引入了Java 鎖的機制,而一不小心就會產生Java 執行緒死鎖的多執行緒問題,因為不同的執行緒都在等待哪些根本不可能被釋放的鎖,導致所有的工作都無法完成。

    假設有兩個飢餓的人,他們必須共享刀叉並輪流吃飯,他們都需要獲得兩個鎖,共享刀和共享叉。假如線程A獲得了刀,而線程B獲得了叉。線程A就會進入阻塞狀態來等待獲得叉,而線程B則主帥來等待線程A所擁有的刀。這只是人為設計的例子,單儘管在運行時很難探測到,這類情況卻時常發生。

    3、線程多了會將服務資源耗盡形成死機、當機

    線程數太多有可能造成系統創建大量線程,而導致消耗完系統記憶體以及CPU的“過渡切換”,造成系統的死機,那麼我們改如果解決這類問題呢?

    某些系統資源是有限的,如檔案描述。多執行緒程式可能會耗盡資源,因為每個執行緒都可能希望有一個這樣的資源。如果執行緒數相當大,或某個資源的侯選線 程數遠遠超過了可用的資源數則最好使用資源池。一個最好的範例是資料庫連接池。只要線程需要使用一個資料庫連接,它就從池中取出一個,使用以後再將它返回池中。 資源池也稱為資源庫。

    多執行緒應用開發的注意事項很多,希望大家在日後的工作中可以慢慢體會它 的危險所在。

    七、多執行緒注意事項

    執行緒之間相互配合,完成某項工作,例如:一個執行緒修改了一個物件的值, 而另一個執行緒感知到了變化,然後進行對應的操作,整個過程開始於一個線程, 而最終執行又是另一個線程。前者是生產者,後者就是消費者,這種模式隔離了「做什麼」(what)和「怎麼做」(How),簡單的辦法是讓消費者線程不斷地循環檢查變數是否符合預期在while循環中設定不滿足的條件,如果條件滿足則退出while 循環,從而完成消費者的工作。

    卻有以下問題:

    • 難以確保及時性。

    • 難以降低開銷。如果降低睡眠的時間,例如休眠 1 毫秒,這樣消費者能 更迅速地發現條件變化,但是卻可能消耗更多的處理器資源,造成了無端的浪費。

    等待/通知機制:是指一個執行緒A 呼叫了物件O 的wait()方法進入等待狀態,而另一個執行緒B 呼叫了物件O的notify()或notifyAll()方法,在執行緒A 收到通知後從物件O 的wait() 方法返回,進而執行後續操作。上述兩個執行緒透過物件 O 來完成交互,而物件 上的 wait()和 notify/notifyAll()的關係就如同開關訊號一樣,用來完成等待方和通 知方之間的交互工作。

    notify():通知一個在物件上等待的線程,使其從wait 方法返回,而返回的前提是該線程獲取到了對象的鎖,沒有獲得鎖的線程重新進入WAITING 狀態。

    notifyAll():通知所有等待在該物件上的執行緒

    wait():呼叫該方法的執行緒進入WAITING 狀態,只有等待另外執行緒的通知或被中斷才會回傳.需要注意,呼叫wait()方法後,會釋放物件的鎖。

    wait(long):超時等待一段時間,這裡的參數時間是毫秒,也就是等待長達n 毫秒,如果沒有 通知就超時返回。

    wait (long,int):對於超時時間更細粒度的控制,可以達到奈秒

    等待和通知的標準範式等待方遵循如下原則。

    • 取得物件的鎖定。

    • 如果條件不滿足,那麼呼叫物件的 wait()方法,被通知後仍要檢查條件。

    • 條件滿足則執行對應的邏輯。

    Java中的多執行緒共享變數與協作機制

    #通知方遵循以下原則:

    • ##取得物件的鎖定。

    • 改變條件。

    • 通知所有等待在物件上的執行緒。

    Java中的多執行緒共享變數與協作機制

    在呼叫wait()、notify()系列方法之前,執行緒必須要取得該物件的物件層級鎖,也就是只能在同步方法或同步區塊中呼叫wait()方法、notify()系列方法,進入wait()方法後,當前執行緒釋放鎖,在從wait()返回前,執行緒與其他執行緒競爭重新獲得鎖,執行notify()系列方法的執行緒退出呼叫了notifyAll 的synchronized 程式碼區塊的時候後,他們就會去競爭。如果其中一個執行緒獲得了該物件鎖定,它就會繼續往下執行,在它退出synchronized 程式碼區塊,釋放鎖定後,其他的已經被喚醒的執行緒將會繼續競爭取得該鎖定,一直進行下去,直到所有被喚醒的執行緒都執行完畢。

    notify 和notifyAll 應該用誰

    盡可能用notifyAll(),謹慎使用notify(),因為notify()只會喚醒一個線程,我們無法確保被喚醒的這個執行緒一定就是我們需要喚醒的執行緒。

    以上是Java中的多執行緒共享變數與協作機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

    在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

    突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

    Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

    PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

    PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

    PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

    PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

    Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

    膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

    PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

    PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

    PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

    PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

    創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

    Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

    See all articles