免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
線程安全總結(二)

關于線程安全總結(-)請看 http://www.javaeye.com/topic/806990  ,發(fā)該貼后,很多朋友都發(fā)站內(nèi)消息問我一些問題,我把回復整理成一篇帖子。敬請高人手下留情,小可謝過了。

 

 

      站內(nèi)很多人都問我,所謂線程的“工作內(nèi)存”到底是個什么東西?有的人認為是線程的棧,其實這種理解是不正確的。看看JLS(java語言規(guī)范)對線程工作內(nèi)存的描述,線程的working memory只是cpu的寄存器和高速緩存的抽象描述。

 

      可能 很多人都覺得莫名其妙,說JVM的內(nèi)存模型,怎么會扯到cpu上去呢?在此,我認為很有必要闡述下,免得很多人看得不明不白的。先拋開java虛擬機不談,我們都知道,現(xiàn)在的計算機,cpu在計算的時候,并不總是從內(nèi)存讀取數(shù)據(jù),它的數(shù)據(jù)讀取順序優(yōu)先級是:寄存器-高速緩存-內(nèi)存。線程耗費的是CPU,線程計算的時候,原始的數(shù)據(jù)來自內(nèi)存,在計算過程中,有些數(shù)據(jù)可能被頻繁讀取,這些數(shù)據(jù)被存儲在寄存器和高速緩存中,當線程計算完后,這些緩存的數(shù)據(jù)在適當?shù)臅r候應該寫回內(nèi)存。當個多個線程同時讀寫某個內(nèi)存數(shù)據(jù)時,就會產(chǎn)生多線程并發(fā)問題,涉及到三個特性:原子性,有序性,可見性。在《線程安全總結》這篇文章中,為了理解方便,我把原子性和有序性統(tǒng)一叫做“多線程執(zhí)行有序性”。支持多線程的平臺都會面臨這種問題,運行在多線程平臺上支持多線程的語言應該提供解決該問題的方案。

 

       那么,我們看看JVM,JVM是一個虛擬的計算機,它也會面臨多線程并發(fā)問題,java程序運行在java虛擬機平臺上,java程序員不可能直接去控制底層線程對寄存器高速緩存內(nèi)存之間的同步,那么java從語法層面,應該給開發(fā)人員提供一種解決方案,這個方案就是諸如 synchronized, volatile,鎖機制(如同步塊,就緒隊列,阻塞隊列)等等。這些方案只是語法層面的,但我們要從本質上去理解它,不能僅僅知道一個 synchronized 可以保證同步就完了。   在這里我說的是jvm的內(nèi)存模型,是動態(tài)的,面向多線程并發(fā)的,沿襲JSL的“working memory”的說法,只是不想牽扯到太多底層細節(jié),因為 《線程安全總結》這篇文章意在說明怎樣從語法層面去理解java的線程同步,知道各個關鍵字的使用場景。

 

      今天有人問我,那 java的線程不是有棧嗎?難道棧不是工作內(nèi)存嗎?工作內(nèi)存這四個字得放到具體的場景中描述,方能體現(xiàn)它具體的意義,在描述JVM的線程同步時,工作內(nèi)存指的是寄存器和告訴緩存的抽象描述,具體請自行參閱JLS。上面講的都是動態(tài)的內(nèi)存模型,甚至已經(jīng)超越了JVM的范圍,那么JVM的內(nèi)存靜態(tài)存儲是怎么劃分的?今天還有人問我,jvm的內(nèi)存模型不是有eden區(qū)嗎?也不見你提起。我跟他說,這是兩個角度去看的,甚至是兩個不同的范圍,動態(tài)的線程同步的內(nèi)存模型,涵蓋了cpu,寄存器,高速緩存,內(nèi)存;JVM的靜態(tài)內(nèi)存儲模型只是一種對內(nèi)存的物理劃分而已,它只局限在內(nèi)存,而且只局限在JVM的內(nèi)存。那些什么線程棧,eden區(qū)都僅僅在JVM內(nèi)存。

 

      說說JVM的線程棧和有個朋友反復跟我糾結的eden區(qū)吧。JVM的內(nèi)存,被劃分了很多的區(qū)域:

1.程序計數(shù)器
每一個Java線程都有一個程序計數(shù)器來用于保存程序執(zhí)行到當前方法的哪一個指令。
2.線程棧
線程的每個方法被執(zhí)行的時候,都會同時創(chuàng)建一個幀(Frame)用于存儲本地變量表、操作棧、動態(tài)鏈接、方法出入口等信息。每一個方法的調用至完成,就意味著一個幀在VM棧中的入棧至出棧的過程。如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常;如果VM??梢詣討B(tài)擴展(VM Spec中允許固定長度的VM棧),當擴展時無法申請到足夠內(nèi)存則拋出OutOfMemoryError異常。
3.本地方法棧
4.堆

每個線程的棧都是該線程私有的,堆則是所有線程共享的。當我們new一個對象時,該對象就被分配到了堆中。但是堆,并不是一個簡單的概念,堆區(qū)又劃分了很多區(qū)域,為什么堆劃分成這么多區(qū)域,這是為了JVM 的內(nèi)存垃圾收集,似乎越扯越遠了,扯到垃圾收集了,現(xiàn)在的jvm的gc都是按代收集,堆區(qū)大致被分為三大塊:新生代,舊生代,持久代(虛擬的);新生代又分為eden區(qū),s0區(qū),s1區(qū)。新建一個對象時,基本小的對象,生命周期短的對象都會放在新生代的eden區(qū)中,eden區(qū)滿時,有一個小范圍的 gc(minor gc),整個新生代滿時,會有一個大范圍的gc(major gc),將新生代里的部分對象轉到舊生代里。
5. 方法區(qū)
其實就是永久代(Permanent Generation),方法區(qū)中存放了每個Class的結構信息,包括常量池、字段描述、方法描述等等。VM Space描述中對這個區(qū)域的限制非常寬松,除了和Java堆一樣不需要連續(xù)的內(nèi)存,也可以選擇固定大小或者可擴展外,甚至可以選擇不實現(xiàn)垃圾收集。相對來說,垃圾收集行為在這個區(qū)域是相對比較少發(fā)生的,但并不是某些描述那樣永久代不會發(fā)生GC(至 少對當前主流的商業(yè)JVM實現(xiàn)來說是如此),這里的GC主要是對常量池的回收和對類的卸載,雖然回收的“成績”一般也比較差強人意,尤其是類卸載,條件相當苛刻。
6.常量池
 Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項信息是常量表(constant_pool table),用于存放編譯期已可知的常量,這部分內(nèi)容將在類加載后進入方法區(qū)(永久代)存放。但是Java語言并不要求常量一定只有編譯期預置入 Class的常量表的內(nèi)容才能進入方法區(qū)常量池,運行期間也可將新內(nèi)容放入常量池(最典型的String.intern()方法)。

 

關于垃圾收集,在此不多說,流到垃圾收集那一章再詳細說吧。關于java的同步,其實還有基于 CPU原語的比較并交換的非阻塞算法(CAS),不過這個在java的并發(fā)包里已經(jīng)實現(xiàn)了很多,因此關于這點,就留到java并發(fā)包那一章介紹吧。后面我會專門寫一篇文章,JVM內(nèi)存與垃圾收集。

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
2萬字長文包教包會 JVM 內(nèi)存結構 保姆級學習筆記
Java:JVM知識點梳理
JVM內(nèi)存結構
JVM_運行機制 了解與深入
4 個關于Java 虛擬機內(nèi)存的問題?
JVM內(nèi)存區(qū)域劃分
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服