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

歡迎訪問 生活随笔!

生活随笔

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

java

java内存块_JVM上的并发和Java内存模型之同步块笔记

發布時間:2025/3/21 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java内存块_JVM上的并发和Java内存模型之同步块笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文來自 圖靈社區@fairjm

轉截請注明出處

這個是書的筆記 書可以在safaribooksonline看,話說這個真的是一個很好的讀外文書的網站啊,一個月39刀就可以暢想全站的書,很值。(訂訂訂訂訂

因為是筆記所以覺得散不是你的錯覺...因為本來就是散的...

筆記記錄了一些概念 方便復習回顧的時候看 更多內容可以戳上面的鏈接

Scala的內存模型 多線程能力 和它的線程間同步全部繼承自JVM

所有的抽象都有一定程度的泄漏 (all abstractions are to some extent leaky)

Processes and Threads

這通常是OS的任務:指派程序的執行部分給特定的處理器 - 這個機制被稱為多任務,并且這對于計算機用戶來說是透明的。

時間片(time slices)

一個進程是正被執行的計算機程序的實例。兩個進程不能直接讀取彼此的內存或者同時使用大部分的資源,使用多進程來表述多任務會非常麻煩 。

在同一個進程中互相獨立的運算單元被稱為線程。在典型的操作系統中,線程的數量比進程多得多。

每一個線程在程序運行時描述了當前的狀態:通過程序棧和程序計數器。

當我們說程序執行了一個動作(比如向內存寫入內容) 我們的意思是一個處理器執行了執行這個動作的線程。(注意這邊的分句,我自己從onenote上粘貼上來都看了好幾遍...)

OS線程是操作系統提供的編程設置 通常通過OS相關的編程接口來暴露出來被使用

在同一個進程中的分隔的線程共享同一區域的內存,通過讀寫內存來彼此交互。另一個來定義進程的方式是: 一系列的OS線程和這些線程共享的內存和資源。

系統周期性地指派不同的OS線程到CPU核心中來允許計算在所有處理器中進行。

java.lang.Thread Java的線程是直接映射到系統線程的 這意味著Java線程的行為是和OS線程是非常相似的

創建和啟動線程

當JVM進程啟動時 他默認會創建一些線程。最重要的線程是主線程(main thread) 執行程序的 main方法。這個線程的名字就叫main。

Thread的狀態:

剛被創建時是 new

當被執行時是 runnable

結束執行是 terminated

啟動一個獨立的線程包含兩步:

1 創建線程對象

2 用start方法執行

object ThreadsCreation extends App {

class MyThread extends Thread {

override def run(): Unit = {

println("New thread running.")

}

}

val t = new MyThread

t.start()

t.join()

println("New thread joined.")

}

join方法是中止main線程的運行直到t線程運行完畢

執行這個方法 將main線程轉換到了 waiting 狀態

等待的線程放棄了他的執行機會 OS可以將處理器用于其他的線程

注意: 等待的線程提醒OS它們正在等待某個狀態并且 停止消耗 CPU周期 而不是重復地檢查這個狀態

sleep方法將線程放入 timed waiting 狀態

OS同樣可以將本該運行這個線程的處理器用來運行其他的線程

確定性: 特定的輸入 程序總會產生相同的輸出 而不管OS選擇的執行調度有什么不同

由OS選擇的調度不同而會對相同輸出產生不同結果的稱為 不確定性

大多數的多線程程序是非確定性的 這也是為什么多線程編程如此困難的原因

原子性執行(Atomic execution)

競態條件(race condition) 是一種現象:并發程序的輸出依賴于語句的執行調度。

不一定是不正確的行為。

但如果一些調度的結果是我們不預期的 那么這個競態條件就可以考慮是一個程序錯誤

原子性執行:代碼塊的原子執行意味著代碼中的語句不能由執行這段代碼的線程和另一個執行這段代碼的線程交錯執行。

在原子性執行中 要么所要執行的代碼都執行了 要么都沒執行

可以通過同步塊保證原子性:

def getUniqueId() = this.synchronized {

val freshUid = uidCount + 1

uidCount = freshUid

freshUid

}

在錯誤的對象上同步會造成比較難以找到的并發錯誤。

每一個JVM中創建的對象都會有一個特殊的實體成為內部鎖(intrinsic lock)或者成為監視器(monitor) 用來保證只有一個線程可以執行在這個對象上的同步塊

當T線程執行在x對象的同步塊時 我們可以說 T線程獲得了x的監視器的所有權。當線程執行完這個同步塊 我們說他釋放了這個監視器。

同步塊語句是線程內通信的基本機制。無論何時,當多個線程要訪問并修改在同一個對象中的字段時 你應該使用同步塊。

重排序(reordering)

同步塊也不是沒有開銷的

對字段進行寫入將更加昂貴

同步塊的性能損失程度取決于JVM實現 但通常不會很大

你可能會趨向于避免使用同步塊當你覺得這里沒有什么不好的語句交互執行的情況,比如上面那個例子一樣(就是上面的代碼沒加同步塊被多個線程訪問)。永遠不要這么做!(永遠不要高估自己)

object ThreadSharedStateAccessReordering extends App {

for (i

var a = false

var b = false

var x = -1

var y = -1

val t1 = thread {

a = true

y = if (b) 0 else 1

}

val t2 = thread {

b = true

x = if (a) 0 else 1

}

t1.join()

t2.join()

assert(!(x == 1 && y == 1), s"x = $x, y = $y")

}

}

比如這個例子,我們的預期是0 0,10,0 1。1 1是我們所不預期的。

理論上不管我們運行多少次 永遠不會有 x=1 y=1的情況發生(所以assert不會不成立 也就不會拋錯)

但實際運行就會..

JVM允許重排序由一個線程執行的特定程序的語句 只要這個重排序不會改變這個線程的序列化執行語義。(the JVM is allowed to reorder certain program statements executed by one thread as long as it does not change the serial semantics of the program for that particular thread)

PS 這里簡單說下:

a = true

y = if (b) 0 else 1

y = if (b) 0 else 1

a = true

對于序列化執行來說,這兩個并沒什么不同(不會產生不同的結果),所以這兩個語句是可以重排序(不需要按照指令的執行順序)

因為一些處理器不總是會按照程序的指令順序執行

而且 線程也不需要將他們做的改動立馬寫入主存 而是暫時存在處理器的寄存器中緩存。這樣可以最大化程序的運行效率并且允許更好的編譯器優化。

以上的錯誤是我們假定線程中所有的寫操作都可以立馬被其他線程看到。我們需要應用一些合適的同步來確保一個線程修改被另一個線程看到的可見性。

同步塊是其中一種實現這個可見性的同步方式。同步塊不僅確保原子性也確保可見性。

總結

以上是生活随笔為你收集整理的java内存块_JVM上的并发和Java内存模型之同步块笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。