日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

深入理解Java虚拟机——第十二章——Java内存模型与线程

發(fā)布時間:2024/4/17 java 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解Java虚拟机——第十二章——Java内存模型与线程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

硬件效率與一致性

處理器需要與內(nèi)存交互,但處理器運算速度與對內(nèi)存的I/O操作速度相差幾個數(shù)量級,因此現(xiàn)代操作系統(tǒng)不得不加入盡可能接近處理器運算速度的高速緩存來作為內(nèi)存與處理器之前的緩沖。這樣處理器就不用等待緩慢的內(nèi)存讀寫。

Java內(nèi)存模型

主存與工作內(nèi)存

Java內(nèi)存模型的主要目的是定義程序中各個變量的訪問規(guī)則。這里的變量和Java編程中的變量有所區(qū)別,這里指的是實例字段、靜態(tài)字段和構成數(shù)組對象的元素,不包括局部變量和方法參數(shù),因為是線程私有的,不會被共享,自然也不存在競爭問題。

Java內(nèi)存模型規(guī)定所有的變量都存儲在主內(nèi)存中。每條線程還有自己的工作內(nèi)存,線程的工作內(nèi)存存儲了被該線程使用到的變量的主內(nèi)存副本拷貝。變量的所有操作(讀取、賦值等)都必須在工作內(nèi)存中運行, 而不能直接讀寫主內(nèi)存中的變量。

內(nèi)存間交互操作

lock、unlock、read、load、use、assign、store、write。

read和load、store和write的操作必須是順序執(zhí)行,但可以不用連續(xù),比如read a、readb b、load b、load a。

?8種操作的規(guī)則:

  • 一個變量在同一時刻只允許一條線程對其進行l(wèi)ock操作,但lock操作可以被同一線程執(zhí)行多次,多次lock后,只有執(zhí)行相同次數(shù)的unlock,變量才會被解鎖。
  • 對一個變量lock,那么會清空工作內(nèi)存中該變量的值,需要重新load或assign這個值。
  • 對一個變量unlock之前,必須將變量同步回主內(nèi)存

volatile變量的特殊規(guī)則

volatile可以說是最輕量級的同步機制。具備兩種特性:

  • 保證此變量對所有線程的可見性。可見性指一條線程修改了值后其它線程立即可知。普通線程不具備這個特性,必須得刷回主內(nèi)存后值后才對其它線程可見。但這種特性并不能保證線程安全,具體來說無法保證變量的一致性。如多線程的++操作,volatile只能保證讀變量時值是正確的,但是多個線程一起寫變量,某個線程寫的快,其它線程的變量就會都被廢棄。在不符合下面兩條規(guī)則的場景還是需要加鎖(JUC或synchronized)來保證原子性:
  • 運算結果并不依賴當前值,或者能夠確保只有單一的線程能夠修改變量的值
  • 變量不需要與其它的狀態(tài)變量共同參與不變約束。(不變約束就是比如說lower<upper,初始值分別為0和10,同一時刻,線程1調(diào)用setLower(8),線程2調(diào)用setUpper(2),執(zhí)行上完全沒問題,但是現(xiàn)在的lower和upper的值就變?yōu)榱?span lang="en-us">8和2這種無效的數(shù)據(jù)了
  • 禁止指令重排序優(yōu)化。加入內(nèi)存屏障,使得CPU的Cache寫入內(nèi)存,該操作會使別的CPU無效化其Cache。從硬件來講,指令重排序是將多條指令不按程序規(guī)定分開發(fā)送給各相應電路單元處理。
  • volatie的讀和普通度的性能消耗沒什么區(qū)別,但是寫操作則可能會慢一些。

    volatile對于操作的規(guī)則:

    • read、load、use操作必須連續(xù)出現(xiàn),即保證每次都從主內(nèi)存讀取最新的值。
    • assign、store、write操作必須連續(xù)出現(xiàn),即保證每次都把修改結果刷新到主內(nèi)存

    64位的數(shù)據(jù)允許分成兩次32位的操作來執(zhí)行,但目前虛擬機都把其作為原子操作來處理,因此使用的時候不需要專門設置為volatile。

    volatile的基本數(shù)據(jù)類型能解決不同線程對get/set方法的執(zhí)行,因為基本數(shù)據(jù)類型的操作是原子性的,即對其修改不依賴自身而是依賴傳入的值,因此執(zhí)行set方法不會說執(zhí)行到一半就切到另一個線程去get。

    原子性、可見性、有序性

    原子性:即操作的原子性,上述8個操作中除了lock和unlock外都是

    可見性:當一個線程修改了共享變量值后,其它線程能立即得知這個修改。除了volatile外synchronized和final也能實現(xiàn)可見性。synchronized可見性是由“在unlock之前,必須把變量同步回主內(nèi)存”實現(xiàn)的。final是在構造器中一旦初始化完成,并且this引用沒有逃逸,那么在其它線程中就能看見final字段的值。

    有序性:線程內(nèi)是有序的,線程之間是無序的。通過volatile和synchronized來提供線程之間有序。

    Java與線程

    線程的實現(xiàn)

    Java在不同硬件和操作系統(tǒng)下對線程的操作統(tǒng)一處理

    線程實現(xiàn)主要有3種方式:

  • 內(nèi)核實現(xiàn):直接用操作系統(tǒng)內(nèi)核支持的線程,這種線程由內(nèi)核完成線程切換。一般不會直接去使用內(nèi)核線程,而是使用內(nèi)核線程的高級接口——輕量級進程,也就是通常意義上的線程。
  • 使用用戶線程實現(xiàn):一個線程只要不是內(nèi)核線程,就可以認為是用戶線程,比如輕量級進程。但這種是建立在內(nèi)核上的,許多操作都要系統(tǒng)調(diào)用,效率會受限制。因此用戶線程建立在用戶空間的線程庫上,用戶線程的建立、同步、銷毀、調(diào)度完全在用戶態(tài)中完成,不需要內(nèi)核調(diào)度。
  • 使用用戶線程加輕量級進程混合實現(xiàn)。
  • Java線程調(diào)度

    協(xié)同式線程調(diào)度和搶占式線程調(diào)度。

    • 協(xié)同式線程調(diào)度:線程的執(zhí)行時間由線程本身控制,線程執(zhí)行完后,主動通知系統(tǒng)切換到另一個線程上。
    • 搶占式線程調(diào)度:線程由系統(tǒng)來分配執(zhí)行時間,線程的切換不由線程本身決定(Thread.yield()可以讓出執(zhí)行時間,但是線程本身無法獲取執(zhí)行時間)。Java一共有10個級別的線程優(yōu)先級。Java線程是通過映射到系統(tǒng)的原生線程實現(xiàn)的,因此線程調(diào)度是取決于系統(tǒng)。

    狀態(tài)轉(zhuǎn)換

    Java定義了5種線程狀態(tài)(等待有兩種),在任意一個時間點,一個線程只能有一個狀態(tài)。

    • 新建(new):創(chuàng)建后尚未啟動的線程
    • 運行(runable):包括了操作系統(tǒng)中的running和ready,即處于此狀態(tài)中的線程有可能正在運行,也有可能在等待CPU為其分配執(zhí)行時間
    • 等待: 無限期等待(waiting):處于這種狀態(tài)的線程不會被CPU分配時間,要等待被其它線程喚醒。以下方法會讓線程進入無限期等待:
      • 沒有設置timeout的Object.wait()方法
      • 沒有設置timeout的Thread.join()方法
      • LockSupport.park()方法
      限期等待(timed waiting):處于這種狀態(tài)的線程不會被CPU分配時間,不過不是等待喚醒,而是在一定時間后會由系統(tǒng)自動喚醒。以下方法會讓線程進入限期等待:
      • 設置timeout的Object.wait()方法
      • 設置timeout的Thread.join()方法
      • Thread.sleep()方法
      • LockSupport.parkNanos()方法
      • LockSupport.parkUntil()方法
    • 阻塞(blocked):線程被阻塞,與等待的區(qū)別是,阻塞是等待獲取一個排他鎖,這個時間將在另一個線程放棄這個鎖的時候發(fā)生。等待狀態(tài)是等待一段時間或喚醒狀態(tài)發(fā)生。在程序進入同步區(qū)域的時候,線程進入這個狀態(tài)。
    • 結束:已終止線程的狀態(tài),線程結束執(zhí)行。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/yjou/p/11265219.html

    總結

    以上是生活随笔為你收集整理的深入理解Java虚拟机——第十二章——Java内存模型与线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。