摘要:我們需要先了解這些概念。在中,其表現(xiàn)在對于共享變量的某些操作,是不可分的,必須連續(xù)的完成。有序性有序性指的是程序按照代碼的先后順序執(zhí)行。
JMM(java內(nèi)存模型),由于并發(fā)程序要比串行程序復(fù)雜很多,其中一個重要原因是并發(fā)程序中數(shù)據(jù)訪問一致性和安全性將會受到嚴重挑戰(zhàn)。如何保證一個線程可以看到正確的數(shù)據(jù)呢?這個問題看起來很白癡。對于串行程序來說,根本就是小菜一碟,如果你讀取一個變量,這個變量的值是1,那么你讀取到的一定是1,就是這么簡單的問題在并行程序中居然變得復(fù)雜起來。事實上,如果不加控制地任由線程胡亂并行,即使原本是1的數(shù)值,你也可能讀到2。因此我們需要在深入了解并行機制的前提下,再定義一種規(guī)則,保證多個線程間可以有小弟,正確地協(xié)同工作。而JMM也就是為此而生的。
JMM關(guān)鍵技術(shù)點都是圍繞著多線程的原子性、可見性、有序性來建立的。我們需要先了解這些概念。
原子性原子性是指操作是不可分的,要么全部一起執(zhí)行,要么不執(zhí)行。在java中,其表現(xiàn)在對于共享變量的某些操作,是不可分的,必須連續(xù)的完成。比如a++,對于共享變量a的操作,實際上會執(zhí)行3個步驟:
1.讀取變量a的值,假如a=1
2.a的值+1,為2
3.將2值賦值給變量a,此時a的值應(yīng)該為2
這三個操作中任意一個操作,a的值如果被其他線程篡改了,那么都會出現(xiàn)我們不希望出現(xiàn)的結(jié)果。所以必須保證這3個操作是原子性的,在操作a++的過程中,其他線程不會改變a的值,如果在上面的過程中出現(xiàn)其他線程修改了a的值,在滿足原子性的原則下,上面的操作應(yīng)該失敗。
java中實現(xiàn)原子操作的方法大致有2種:鎖機制、無鎖CAS機制,后面的章節(jié)中會有介紹。
可見性可見性是指一個線程對共享變量的修改,對于另一個線程來說是否是可以看到的。有些同學(xué)會說修改同一個變量,那肯定是可以看到的,難道線程眼盲了?
為什么會出現(xiàn)這種問題呢?
看一下java線程內(nèi)存模型:
我們定義的所有變量都儲存在主內(nèi)存中
每個線程都有自己獨立的工作內(nèi)存,里面保存該線程使用到的變量的副本(主內(nèi)存中該變量的一份拷貝)
線程對共享變量所有的操作都必須在自己的工作內(nèi)存中進行,不能直接從主內(nèi)存中讀寫(不能越級)
不同線程之間也無法直接訪問其他線程的工作內(nèi)存中的變量,線程間變量值的傳遞需要通過主內(nèi)存來進行。(同級不能相互訪問)
線程需要修改一個共享變量X,需要先把X從主內(nèi)存復(fù)制一份到線程的工作內(nèi)存,在自己的工作內(nèi)存中修改完畢之后,再從工作內(nèi)存中回寫到主內(nèi)存。
如果線程對變量的操作沒有刷寫回主內(nèi)存的話,僅僅改變了自己的工作內(nèi)存的變量的副本,那么對于其他線程來說是不可見的。
而如果另一個變量沒有讀取主內(nèi)存中的新的值,而是使用舊的值的話,同樣的也可以列為不可見。
線程A對共享變量的修改要被線程B及時看到的話,需要進過以下步驟:
1.線程A在自己的工作內(nèi)存中修改變量之后,需要將變量的值刷新到主內(nèi)存中
2.線程B要把主內(nèi)存中變量的值更新到工作內(nèi)存中
關(guān)于線程可見性的控制,可以使用volatile、synchronized、鎖來實現(xiàn),后面章節(jié)會有詳細介紹。
有序性
有序性指的是程序按照代碼的先后順序執(zhí)行。
為了性能優(yōu)化,編譯器和處理器會進行指令沖排序,有時候會改變程序語句的先后順序,比如程序。
int a = 1; //1
int b = 20; //2
int c = a + b; //3
編譯器優(yōu)化后可能變成
int b = 20; //1
int a = 1; //2
int c = a + b; //3
上面這個例子中,編譯器調(diào)整了語句的順序,但是不影響程序的最終結(jié)果。
在單例模式的實現(xiàn)上有一種雙重檢驗鎖定的方式,代碼如下:
public class Singleton { static Singleton instance; static Singleton getInstance(){ if (instance == null) { synchronized(Singleton.class) { if (instance == null) instance = new Singleton(); } } return instance; } }
我們先看instance = new Singleton();
未被編譯器優(yōu)化的操作:
指令1:分配一款內(nèi)存M
指令2:在內(nèi)存M上初始化Singleton對象
指令3:將M的地址賦值給instance變量
編譯器優(yōu)化后的操作指令:
指令1:分配一塊內(nèi)存S
指令2:將M的地址賦值給instance變量
指令3:在內(nèi)存M上初始化Singleton對象
現(xiàn)在有2個線程,剛好執(zhí)行的代碼被編譯器優(yōu)化過,過程如下:
最終線程B獲取的instance是沒有初始化的,此時去使用instance可能會產(chǎn)生一些意想不到的錯誤。
現(xiàn)在比較好的做法就是采用靜態(tài)內(nèi)部內(nèi)的方式實現(xiàn):
public class SingletonDemo { private SingletonDemo() { } private static class SingletonDemoHandler{ private static SingletonDemo instance = new SingletonDemo(); } public static SingletonDemo getInstance() { return SingletonDemoHandler.instance; } }喜歡就關(guān)注我吧
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75936.html
摘要:有三種狀態(tài)運行關(guān)閉終止。類類,提供了一系列工廠方法用于創(chuàng)建線程池,返回的線程池都實現(xiàn)了接口。線程池的大小一旦達到最大值就會保持不變,在提交新任務(wù),任務(wù)將會進入等待隊列中等待。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。 這是java高并發(fā)系列第19篇文章。 本文主要內(nèi)容 介紹Executor框架相關(guān)內(nèi)容 介紹Executor 介紹ExecutorService 介紹線程池ThreadP...
摘要:方法由兩個參數(shù),表示期望的值,表示要給設(shè)置的新值。操作包含三個操作數(shù)內(nèi)存位置預(yù)期原值和新值。如果處的值尚未同時更改,則操作成功。中就使用了這樣的操作。上面操作還有一點是將事務(wù)范圍縮小了,也提升了系統(tǒng)并發(fā)處理的性能。 這是java高并發(fā)系列第21篇文章。 本文主要內(nèi)容 從網(wǎng)站計數(shù)器實現(xiàn)中一步步引出CAS操作 介紹java中的CAS及CAS可能存在的問題 悲觀鎖和樂觀鎖的一些介紹及數(shù)據(jù)庫...
摘要:這里呢,我直接給出高并發(fā)場景通常都會考慮的一些解決思路和手段結(jié)尾如何有效的準備面試中并發(fā)類問題,我已經(jīng)給出我的理解。 showImg(https://segmentfault.com/img/bV7Viy?w=550&h=405); 主題 又到面試季了,從群里,看到許多同學(xué)分享了自己的面試題目,我也抽空在網(wǎng)上搜索了一些許多公司使用的面試題,目前校招和社招的面試題基本都集中在幾個大方向上...
摘要:并發(fā)編程的挑戰(zhàn)并發(fā)編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發(fā)執(zhí)行。的實現(xiàn)原理與應(yīng)用在多線程并發(fā)編程中一直是元老級角色,很多人都會稱呼它為重量級鎖。 并發(fā)編程的挑戰(zhàn) 并發(fā)編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發(fā)執(zhí)行。如果希望通過多線程執(zhí)行任務(wù)讓程序運行的更快,會面臨非常多的挑戰(zhàn):(1)上下文切換(2)死...
摘要:假設(shè)不發(fā)生編譯器重排和指令重排,線程修改了的值,但是修改以后,的值可能還沒有寫回到主存中,那么線程得到就是很自然的事了。同理,線程對于的賦值操作也可能沒有及時刷新到主存中。線程的最后操作與線程發(fā)現(xiàn)線程已經(jīng)結(jié)束同步。 很久沒更新文章了,對隔三差五過來刷更新的讀者說聲抱歉。 關(guān)于 Java 并發(fā)也算是寫了好幾篇文章了,本文將介紹一些比較基礎(chǔ)的內(nèi)容,注意,閱讀本文需要一定的并發(fā)基礎(chǔ)。 本文的...
閱讀 1012·2021-11-23 10:11
閱讀 3854·2021-11-16 11:50
閱讀 921·2021-10-14 09:43
閱讀 2713·2021-10-14 09:42
閱讀 2710·2021-09-22 16:02
閱讀 1056·2019-08-29 10:57
閱讀 3378·2019-08-29 10:57
閱讀 2268·2019-08-26 13:52