Java內(nèi)存模型
概述
多任務(wù)是被證明的有效的壓榨處理器能力的方式
一個(gè)服務(wù)端為多個(gè)客戶端提供服務(wù)是常見的場景袜腥,并發(fā)協(xié)調(diào)是否有效大大影響了程序的效率
Java語言和JVM提供了很多工具大大降低了并發(fā)編程的門檻谈为。但程序員不能過度依賴這些語言和框架,才能真正利用好這些工具
服務(wù)器常用的衡量性能量化指標(biāo):TPS, Transactions Per Second; 數(shù)據(jù)庫常用的衡量性能量化指標(biāo):QPS, Queries Per Second
硬件效率與一致性
學(xué)習(xí)Java的并發(fā)泼疑,可以通過物理計(jì)算機(jī)中的并發(fā)問題找到相似點(diǎn),有很大的參考意義。
- 讓計(jì)算機(jī)并發(fā)->充分利用計(jì)算機(jī)的性能谤绳,值得商榷 大多數(shù)運(yùn)算任務(wù),不止是依靠處理器袒哥,還需要與內(nèi)存交互
存儲(chǔ)與CPU性能的差距缩筛,需要在中間加一層高速緩存(Cache),作為內(nèi)存與處理器之間的緩沖堡称。
Cache引入問題:Cache Coherence瞎抛,緩存一致性。每個(gè)處理器都有自己的高速緩存却紧,卻同享同一個(gè)主存桐臊。
此處應(yīng)該有圖:處理器,高速緩存胎撤,主內(nèi)存的關(guān)系
- 除了高速緩存的問題,還有指令亂序執(zhí)行 目的是為了內(nèi)部計(jì)算單元能夠盡量被充分利用
Java內(nèi)存模型
JMM, Java Memory Model, 用于屏蔽各種硬件和操作系統(tǒng)的內(nèi)存訪問差異断凶,達(dá)到多平臺(tái)的一致性伤提;C/C++直接使用物理硬件和操作系統(tǒng)的內(nèi)存模型
在JMM的設(shè)計(jì)上,必須足夠嚴(yán)謹(jǐn)用于保證正確性认烁,也需要保證足夠?qū)捤芍啄校軌蚋玫厥褂糜布母鞣N特性。
主內(nèi)存和工作內(nèi)存
JMM的目標(biāo)定義各個(gè)變量的訪問規(guī)則:存取變量的細(xì)節(jié)
局部變量却嗡,方法參數(shù)都是線程私有舶沛,不會(huì)被共享,不會(huì)出現(xiàn)競爭問題
主內(nèi)存類比物理機(jī)主內(nèi)存稽穆;工作內(nèi)存類比處理器告訴緩存冠王。Working Memory 保存了變量的主內(nèi)存副本,實(shí)際上是拷貝的引用和對(duì)象在某個(gè)線程中訪問到的字段
不同線程的工作內(nèi)存是獨(dú)立的舌镶,這就是容易出現(xiàn)問題的地方
不準(zhǔn)確的對(duì)應(yīng)柱彻。
- 與JVM對(duì)應(yīng):主內(nèi)存->Java堆中的實(shí)例數(shù)據(jù)部分;工作內(nèi)存->虛擬機(jī)棧中的部分區(qū)域
- 與物理機(jī)對(duì)應(yīng):主內(nèi)存->硬件內(nèi)存餐胀;JVM則會(huì)將Working Memory 放在寄存器和高速緩存中
內(nèi)存間的交互
交互的操作都可以視為是原子性的哟楷。除了double和long在某些平臺(tái)有例外
交互操作:
- lock, unlock : 作用于主內(nèi)存變量,標(biāo)示線程的獨(dú)占狀態(tài)
- 作用于主內(nèi)存:read, write
- 作用于工作內(nèi)存:load, store否灾。與執(zhí)行引擎相關(guān):use, assign
交互原則
略微繁瑣卖擅,可以使用“先行發(fā)生”原則來等效保證
對(duì)于 volatile 型變量的特殊規(guī)則
最輕量級(jí)的同步機(jī)制
voatile 的變量具備兩種特性:
- 保證對(duì)于其他線程的可見性:新值對(duì)于其他線程是立即可知的
- 禁止指令重排
值得注意的問題,由于 Java 里面的運(yùn)算并非原子操作墨技,導(dǎo)致操作棧棧頂?shù)闹凳沁^期數(shù)據(jù)惩阶。
如果要安全使用voatile,必須保證下面條件:(核心就是沒有依賴)
- 運(yùn)算結(jié)果不依賴變量的當(dāng)前值(比如直接賦值)扣汪,單一線程訪問(這就是廢話)
- 變量不需要與其他的狀態(tài)變量共同參與不變約束断楷。
可以用于單例模式的創(chuàng)建。如果不適用voatile崭别,則可以用以下代碼:
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
Singleton tmp = instance;
if (tmp == null) {
synchronized(Singlet.class) {
tmp = new Singleton();
}
instance = tmp;
}
}
}
return instance;
}
優(yōu)化版本:
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
Singleton tmp = instance;
if (tmp == null) {
synchronized(Singleton.class) {
instance = new Singleton();
}
}
}
}
return instance;
}