国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

濟(jì)南建設(shè)銀行網(wǎng)站杭州網(wǎng)站定制

濟(jì)南建設(shè)銀行網(wǎng)站,杭州網(wǎng)站定制,公司網(wǎng)站建設(shè)空間,理財(cái)網(wǎng)站模板本文僅是本人對(duì)問題的思考記錄,并沒有實(shí)操驗(yàn)證,有誤請(qǐng)大家評(píng)論指出。 今天見到了一個(gè)經(jīng)典的問題,單核CPU是否有線程可見性問題,學(xué)完操作系統(tǒng)應(yīng)該可以直接回答,不會(huì)有線程安全問題。但如果結(jié)合JVM虛擬機(jī)來(lái)進(jìn)行分析&…

本文僅是本人對(duì)問題的思考記錄,并沒有實(shí)操驗(yàn)證,有誤請(qǐng)大家評(píng)論指出。

今天見到了一個(gè)經(jīng)典的問題,單核CPU是否有線程可見性問題,學(xué)完操作系統(tǒng)應(yīng)該可以直接回答,不會(huì)有線程安全問題。但如果結(jié)合JVM虛擬機(jī)來(lái)進(jìn)行分析,就又麻煩了一點(diǎn)。結(jié)合線程切換和JVM內(nèi)存區(qū)域,本文重新梳理了一下對(duì)這個(gè)問題的思考。

文中可能還有其他問題,例如JDK8之后就沒有方法區(qū)的概念了,

以及最后的data=1只是為了表示對(duì)數(shù)據(jù)進(jìn)行更改,沒有考慮變量存儲(chǔ)位置和引用類型等問題。

1 從JVM內(nèi)存區(qū)域說(shuō)起

我們都知道,JVM的內(nèi)存區(qū)域有兩部分,一部分是線程共享的:堆和方法區(qū)(JDK8之后變?yōu)樵臻g的概念,且位于本地內(nèi)存中),另一部分是線程私有的:虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器。

請(qǐng)?zhí)砑訄D片描述

既然是線程私有的,那么如果有多線程,難道有多個(gè)虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器嗎?答案是否定的。一個(gè)JVM虛擬機(jī)的內(nèi)存區(qū)域就是這樣的。那么問題來(lái)了,一個(gè)線程占有了這三個(gè)私有區(qū),那其他線程到哪去了?我們需要回顧操作系統(tǒng)中的線程和進(jìn)程間的關(guān)系:

線程和進(jìn)程的關(guān)系

王道書里是這么解釋的:進(jìn)程是一個(gè)獨(dú)立的運(yùn)行單位,也是操作系統(tǒng)進(jìn)行資源分配的基本單位。而線程不擁有資源,但卻是CPU調(diào)度的最小單位。

進(jìn)程。它包含三個(gè)部分:PCB(Process Control Block)進(jìn)程控制塊、程序段、數(shù)據(jù)段。其中PCB為核心,該結(jié)構(gòu)常駐內(nèi)存,與進(jìn)程同生共死。切換進(jìn)程的時(shí)候,處理機(jī)狀態(tài)信息必須保存到響應(yīng)的PCB中,以便在該進(jìn)程重新執(zhí)行時(shí),能從斷點(diǎn)繼續(xù)執(zhí)行。

線程。除了有TCB(Thread Control Block)線程控制塊之外,還有其專有的存儲(chǔ)區(qū)。切換線程的時(shí)候,狀態(tài)信息需要保存到TCB中。

這里插入思考一個(gè)問題,為什么線程切換比進(jìn)程切換更輕量級(jí)?

回答這個(gè)問題,我們首先要知道“保存狀態(tài)信息”到底保存了什么?由于一個(gè)進(jìn)程用到的數(shù)據(jù)都會(huì)加載到內(nèi)存中(可能只加載了一部分,通過(guò)虛擬內(nèi)存),所以PCB中保存的都是一些地址引用,而不是數(shù)據(jù)實(shí)體。大概包括:

  • 進(jìn)程描述信息:PID、UID
  • 進(jìn)程控制和管理信息:進(jìn)程狀態(tài)、優(yōu)先級(jí)、代碼入口地址、CPU占用時(shí)間、程序的外存地址等
  • 資源分配清單:I/O設(shè)備信息、代碼段指針、數(shù)據(jù)段指針、堆棧指針、文件描述符等
  • CPU相關(guān)信息:各種寄存器的值、狀態(tài)字

即便是只需要保存地址引用,但仍然需要保存這么多的信息。而線程切換時(shí),TCB需要保存的,相比之下就輕量級(jí)很多:

  • PC程序計(jì)數(shù)器(寄存器)、棧等信息。

這兩個(gè)一對(duì)比,就發(fā)現(xiàn)了切換的代價(jià),線程切換明顯更輕。

線程與進(jìn)程在Android中的表現(xiàn)
一個(gè)Java程序,通過(guò)main()開啟了它的進(jìn)程生涯,承載這個(gè)程序的,就是JVM虛擬機(jī)??梢岳斫鉃?#xff0c;JVM虛擬機(jī)就是這個(gè)java程序的進(jìn)程的概念。

Android的進(jìn)程是什么呢?在Zygote孵化器 fork() 進(jìn)程的時(shí)候,我們發(fā)現(xiàn)它還fork()了虛擬機(jī),準(zhǔn)備好虛擬機(jī)后,反射執(zhí)行了ActivityThread的main()方法,換句話說(shuō),Android中一樣也是一個(gè)虛擬機(jī)對(duì)應(yīng)了一個(gè)APP進(jìn)程。

APP進(jìn)程中可能有很多線程,比如binder線程、用戶自己開辟的線程。這些線程的切換,都通過(guò)TCB來(lái)進(jìn)行現(xiàn)場(chǎng)的保存與恢復(fù)。虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器在內(nèi)存中的地址信息都會(huì)通過(guò)TCB來(lái)進(jìn)行保存和恢復(fù)。

我們還要注意到,TCB和PCB的保存與恢復(fù)類似,都是保存數(shù)據(jù)地址,例如棧信息的數(shù)據(jù)地址、寄存器的數(shù)據(jù)等。線程的棧中有局部變量表,它通過(guò)指針,JVM中線程共享的部分獲取數(shù)據(jù),它本身并不存儲(chǔ)數(shù)據(jù)。線程私有的,是線程各自的局部變量表、程序計(jì)數(shù)器等信息,而并不是數(shù)據(jù)本身。例如下面這張圖所示的虛擬機(jī)棧內(nèi)部結(jié)構(gòu),都是一些指針信息,并沒有保存數(shù)據(jù)本體。

img

到這里,我們來(lái)梳理一下:

  1. App進(jìn)程的切換,本質(zhì)上是對(duì)該進(jìn)程的PCB(程序控制器)的信息進(jìn)行保存與恢復(fù)。其信息具體指向的內(nèi)容,仍然還在內(nèi)存中。
  2. 線程的切換,如果是同一進(jìn)程下的線程切換,本質(zhì)上是對(duì)線程的TCB(線程控制器)的信息進(jìn)行保存與恢復(fù)。其信息具體指向的內(nèi)容,仍然在對(duì)應(yīng)進(jìn)程所擁有的內(nèi)存空間中。

我們來(lái)看到下面這張圖:

請(qǐng)?zhí)砑訄D片描述

為了結(jié)構(gòu)清晰,這里沒有加入多級(jí)Cache緩存,主要為了表達(dá),如果僅是線程切換,只需要切換TCB的信息即可,也就是從上圖藍(lán)線引用切換為粉線引用,而PCB的信息則不需要改動(dòng)。當(dāng)然,如果要切換其他進(jìn)程,就需要對(duì)PCB進(jìn)行保存和恢復(fù)了。

到這,我們最初的問題:“一個(gè)JVM虛擬機(jī)的內(nèi)存區(qū)域就是這樣的,一個(gè)線程占有了虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器,那其他線程到哪去了?”??梢曰卮?#xff0c;其他線程的虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器還在內(nèi)存中,這三者在內(nèi)存中的地址信息存在了TCB(線程控制塊)中。當(dāng)這個(gè)線程需要被調(diào)度的時(shí)候,通過(guò)TCB的地址信息,將這個(gè)線程的數(shù)據(jù)恢復(fù)回來(lái)。

Java的線程是如何實(shí)現(xiàn)的?

我們從啟動(dòng)線程的源碼中也能看到,start()最終調(diào)用到start0()這個(gè)本地方法,這就說(shuō)明Java線程的啟動(dòng)是由JVM底層來(lái)決定的。又提到王道操作系統(tǒng)的內(nèi)容,我們知道線程分為:用戶線程、核心線程、組合線程。Java線程的實(shí)現(xiàn)方式隨不同操作系統(tǒng)而異。

在《深入理解JVM虛擬機(jī)》中說(shuō)到,例如Windows和Linux中,都是使用一對(duì)一的線程模型來(lái)實(shí)現(xiàn)的,一條Java線程對(duì)應(yīng)一條輕量級(jí)進(jìn)程。在Unix平臺(tái)中,可以支持一對(duì)一以及多對(duì)多。但都沒有使用用戶線程,主要原因是,如果使用用戶線程,進(jìn)程就要自己處理線程的創(chuàng)建 、切換和銷毀,但最重要的麻煩在于,很難處理:“阻塞如何處理”、“多處理器時(shí),如何將線程映射到其他處理器上并行執(zhí)行”。

下圖給出用戶線程與輕量級(jí)進(jìn)程1:1的關(guān)系,其中UT為用戶線程(User Thread)同時(shí)也是Java線程,LWP為輕量級(jí)進(jìn)程(LowWeight Process),KLT為內(nèi)核線程(Kernel-Level Thread):

請(qǐng)?zhí)砑訄D片描述
也正是有內(nèi)核線程的參與,即由操作系統(tǒng)介入,把線程作為最小單位進(jìn)行調(diào)度,才使得在多核CPU下,一個(gè)Java進(jìn)程的多個(gè)線程,可以運(yùn)行在不同的處理機(jī)上。

2. 多核CPU的結(jié)構(gòu)圖

鋪墊了這么多,仍然不能切入主題,在討論線程間可見性問題的時(shí)候,避不開緩存一致性問題。我們知道,ALU計(jì)算單元的處理速度遠(yuǎn)高于內(nèi)存數(shù)據(jù)的讀寫速度,所以我們引入了多級(jí)緩存,來(lái)減小這種效率差。為了節(jié)省時(shí)間,我們直接考慮一個(gè)JVM虛擬機(jī)進(jìn)程,在多級(jí)緩存中是如何表現(xiàn)的,且我只畫了二級(jí)緩存:

請(qǐng)?zhí)砑訄D片描述

主存的數(shù)據(jù)很多,緩存中只根據(jù)局部性原理留下了幾個(gè)物理塊。我們先來(lái)梳理幾個(gè)概念,再進(jìn)入線程間可見性問題。

首先,JVM內(nèi)存區(qū)域中的堆和方法區(qū)的“共享”概念,在上面這張圖中就體現(xiàn)了。不同的線程并行跑在不同的CPU中,訪問的都是JVM內(nèi)存區(qū)域中的“共享”區(qū)。但是,由于多級(jí)緩存,Java線程訪問到的只是一份數(shù)據(jù)拷貝,并不是真正對(duì)主存的數(shù)據(jù)做處理。我們首先明確一點(diǎn),緩存中的數(shù)據(jù)是真拷貝,緩存是從主存中拷貝了一整個(gè)物理塊到緩存中來(lái),而不是保存了指向主存的指針。

在不同CPU中對(duì)共享區(qū)域數(shù)據(jù)的修改,在使用“寫回法”的情況下,只要沒出現(xiàn)物理塊的調(diào)換,就不會(huì)將更改后的數(shù)據(jù)更新回主存。其他線程也根本不知道這部分?jǐn)?shù)據(jù)被改了:

請(qǐng)?zhí)砑訄D片描述

這久發(fā)生了線程安全問題,到底應(yīng)該聽誰(shuí)的呢?最后寫回主存的時(shí)候就會(huì)無(wú)法確認(rèn)最后的data到底是2還是3。

Java中通過(guò)volatile、final、synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)線程間可見性

為了解決這種緩存一致性問題,java引入了volatile、final、synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)線程間可見性問題。具體如何做到的,這里就不做多余分析了。通過(guò)線程間可見性關(guān)鍵字,讓對(duì)變量的訪問需要強(qiáng)制從內(nèi)存中重新把數(shù)據(jù)刷回。

3. 最后回到正題,單核CPU會(huì)有線程可見性問題么?

答案是沒有的。還是剛才的例子,現(xiàn)在只有CPU-1,首先來(lái)到線程A,將data從1改為2:

請(qǐng)?zhí)砑訄D片描述

接下來(lái),進(jìn)行線程切換,線程私有區(qū)被切換為了線程B的內(nèi)容,但共有部分并不需要切換,這是進(jìn)程資源,只有在進(jìn)程切換,或者缺頁(yè)等情況發(fā)生的時(shí)候,才會(huì)有所變動(dòng)。

輪到線程B執(zhí)行,線程B也要訪問data變量,通過(guò)局部變量表的指針,找到了位于堆中data的位置,

請(qǐng)?zhí)砑訄D片描述

由于線程B訪問的也是這一塊緩存,即便是沒有緩存一致性協(xié)議,它仍然能夠訪問到最新的值,因?yàn)?strong>這里根本就不存在同一級(jí)別的緩存出現(xiàn)不一致的情況,因?yàn)樗罱K層級(jí)只有一個(gè)緩存。至此,就搞通了為什么單核CPU下的多線程場(chǎng)景,不會(huì)造成線程安全,不會(huì)有線程可見性問題。

當(dāng)然,在進(jìn)行進(jìn)程切換時(shí),或者發(fā)生緩存缺頁(yè)時(shí),進(jìn)程的物理塊可能會(huì)被逐層寫回主存,但這并不影響我們之前的分析。

此外,本文舉的data例子是int變量,暫且認(rèn)為是一個(gè)對(duì)象中的某個(gè)成員變量,所以修改的是堆中某個(gè)對(duì)象的成員變量的值,避免摻雜其他問題。

單核CPU還有必要開啟多線程嗎?
還是有必要的,舉個(gè)例子,其中一個(gè)線程需要進(jìn)行I/O操作,不希望在IO還沒完成的時(shí)候把CPU時(shí)間交給它,浪費(fèi)CPU資源。

4. 參考文獻(xiàn)

《深入理解Java虛擬機(jī)》,周志明

《王道操作系統(tǒng)考研復(fù)習(xí)指導(dǎo)》,王道論壇

http://m.aloenet.com.cn/news/40173.html

相關(guān)文章:

  • 業(yè)務(wù)外包服務(wù)公司朝陽(yáng)seo排名
  • 最好的javascript視頻seo技巧是什么
  • 網(wǎng)站開發(fā)公司成本是什么愛站權(quán)重
  • 國(guó)際購(gòu)物平臺(tái)都有哪些重慶百度快速優(yōu)化
  • 安順網(wǎng)站開發(fā)網(wǎng)站推廣公司大家好
  • 成都網(wǎng)站建設(shè)小程序整站seo外包
  • 自建個(gè)網(wǎng)站怎么做農(nóng)產(chǎn)品推廣方案
  • 網(wǎng)站做網(wǎng)頁(yè)廣告公司經(jīng)營(yíng)范圍
  • 做網(wǎng)站入什么科目網(wǎng)絡(luò)營(yíng)銷公司好不好
  • 開發(fā)高端網(wǎng)站開發(fā)哈爾濱企業(yè)網(wǎng)站seo
  • 專業(yè)網(wǎng)站建設(shè)詳細(xì)方案南陽(yáng)網(wǎng)站優(yōu)化公司
  • wordpress添加商品蘭州seo推廣
  • 婚紗攝影網(wǎng)站建設(shè)網(wǎng)站關(guān)鍵詞優(yōu)化建議
  • 營(yíng)銷技巧五步推銷法北京核心詞優(yōu)化市場(chǎng)
  • 惠州營(yíng)銷型網(wǎng)站建設(shè)杭州專業(yè)seo服務(wù)公司
  • 做網(wǎng)站必看的外國(guó)書籍萬(wàn)能引流軟件
  • 做網(wǎng)站應(yīng)該用多少分辨率志鴻優(yōu)化設(shè)計(jì)官網(wǎng)
  • 天津網(wǎng)約車優(yōu)化百度百科
  • 榆林網(wǎng)站建設(shè)天津谷歌優(yōu)化
  • wordpress分類靜態(tài)專業(yè)培訓(xùn)seo的機(jī)構(gòu)
  • 形象墻設(shè)計(jì)東莞seo靠譜
  • 備案 網(wǎng)站名稱 重復(fù)百度指數(shù)移動(dòng)版
  • 帝國(guó)手機(jī)網(wǎng)站模板我想在百度發(fā)布信息
  • 網(wǎng)站數(shù)據(jù)分析工具有哪些網(wǎng)站推廣seo是什么
  • wamp做的網(wǎng)站外網(wǎng)怎么訪問自媒體推廣渠道有哪些
  • 為客戶做網(wǎng)站的方案上海seo優(yōu)化公司
  • 南昌做網(wǎng)站今日要聞
  • 亳州電商網(wǎng)站建設(shè)南京百度網(wǎng)站推廣
  • 增城網(wǎng)站建設(shè)網(wǎng)站seo優(yōu)化是什么意思
  • 成免費(fèi)crm是什么鄭州網(wǎng)站優(yōu)化