摘要:最后,總結(jié)一下,導(dǎo)致并發(fā)問題的三個源頭分別是原子性一個線程在執(zhí)行的過程當中不被中斷??梢娦砸粋€線程修改了共享變量,另一個線程能夠馬上看到,就叫做可見性。
計算機的 CPU、內(nèi)存、I/O 設(shè)備的速度一直存在較大的差異,依次是 CPU > 內(nèi)存 > I/O 設(shè)備,為了權(quán)衡這三者的速度差異,主要提出了三種解決辦法:
CPU 增加了緩存,均衡和內(nèi)存的速度差異
發(fā)明了進程、線程,分時復(fù)用 CPU,提高 CPU 的使用效率
編譯指令優(yōu)化,更好的利用緩存
三種解決辦法雖然有效,但是也帶來了另外的三個問題,分別就是并發(fā) bug 產(chǎn)生的源頭。
1.可見性問題
如果是單核 CPU,多個線程操作的都是同一個 CPU 緩存,那么一個線程修改了共享變量,另一個線程肯定能馬上看到。
如果是多核 CPU ,每個 CPU 都有自己的緩存,這樣線程對共享變量的修改便對其他線程不可見了。
2.原子性問題
為什么會有線程切換?一個線程在執(zhí)行的過程中,可能會進行耗時的 I/O 操作,這時線程需要等待 I/O 操作完成。線程在等待的過程中,可以釋放 CPU 的使用權(quán),讓另一個線程執(zhí)行,這樣能夠提高 CPU 的使用率。
例如上圖,兩個線程同時對變量 count 加 1,線程 A 在執(zhí)行的過程中切換到了線程 B,最后導(dǎo)致寫入到內(nèi)存的值都是 1,與預(yù)期不符。
3.有序性問題
首先看一段很經(jīng)典的獲取單例對象的代碼:
public class Singleton { private static Singleton instance; //Java 獲取單例對象 public Singleton getInstance(){ if (instance == null){ synchronized (Singleton.class){ if (instance == null){ instance = new Singleton(); } } } return instance; } }
程序的邏輯是:首先判斷 instance 是否為空,如果為空,對其加鎖,然后再判斷是否為空,此時為空的話則初始化 instance 對象。
如果線程 A 和 B 同時執(zhí)行方法,在 synchronized 處,一個線程會被阻塞,假設(shè)被阻塞的是線程 B,此時線程 A 進入并初始化 instance,然后喚醒線程 B,線程 B 進入的時候,發(fā)現(xiàn) instance 不為空了,所以不會創(chuàng)建對象。
但是因為有序性問題的存在,這段代碼也不是想象的那么完美,我們期望的初始化對象的過程是這樣的:1.分配內(nèi)存;2.初始化對象;3.將內(nèi)存地址賦給 instance。但是經(jīng)過編譯優(yōu)化之后,卻是這樣的:
1.分配內(nèi)存
2.將內(nèi)存地址賦給 instance
3.在內(nèi)存上面初始化對象
這樣,如果線程 A 執(zhí)行到了第二步,然后切換到 線程 B,線程 B 就會認為 instance 不為空然后直接返回了,實際上 instance 并沒有初始化。
最后,總結(jié)一下,導(dǎo)致并發(fā)問題的三個源頭分別是
原子性:一個線程在執(zhí)行的過程當中不被中斷。
可見性:一個線程修改了共享變量,另一個線程能夠馬上看到,就叫做可見性。
有序性:編譯指令重排導(dǎo)致的問題。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/74507.html
摘要:今天開始整理學(xué)習(xí)多線程的知識,談?wù)勛钪匾膬蓚€關(guān)鍵字和。但是這樣一個過程比較慢,在使用多線程的時候就會出現(xiàn)問題。有序性有序性是指多線程執(zhí)行結(jié)果的正確性。這種機制在多線程中會出現(xiàn)問題,因此可以通過來禁止重排。 今天開始整理學(xué)習(xí)多線程的知識,談?wù)勛钪匾膬蓚€關(guān)鍵字:volatile和synchronized。 一、三個特性 1、原子性 所謂原子性操作就是指這些操作是不可中斷的,要么執(zhí)行過程...
摘要:因為管理人員是了解手下的人員以及自己負責(zé)的事情的。處理器優(yōu)化和指令重排上面提到在在和主存之間增加緩存,在多線程場景下會存在緩存一致性問題。有沒有發(fā)現(xiàn),緩存一致性問題其實就是可見性問題。 網(wǎng)上有很多關(guān)于Java內(nèi)存模型的文章,在《深入理解Java虛擬機》和《Java并發(fā)編程的藝術(shù)》等書中也都有關(guān)于這個知識點的介紹。但是,很多人讀完之后還是搞不清楚,甚至有的人說自己更懵了。本文,就來整體的...
摘要:因為管理人員是了解手下的人員以及自己負責(zé)的事情的。處理器優(yōu)化和指令重排上面提到在在和主存之間增加緩存,在多線程場景下會存在緩存一致性問題。有沒有發(fā)現(xiàn),緩存一致性問題其實就是可見性問題。 網(wǎng)上有很多關(guān)于Java內(nèi)存模型的文章,在《深入理解Java虛擬機》和《Java并發(fā)編程的藝術(shù)》等書中也都有關(guān)于這個知識點的介紹。但是,很多人讀完之后還是搞不清楚,甚至有的人說自己更懵了。本文,就來整體的...
摘要:另一個是使用鎖的機制來處理線程之間的原子性。依賴于去實現(xiàn)鎖,因此在這個關(guān)鍵字作用對象的作用范圍內(nèi),都是同一時刻只能有一個線程對其進行操作的。 線程安全性 定義:當多個線程訪問某個類時,不管運行時環(huán)境采用何種調(diào)度方式或者這些線程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個類都能表現(xiàn)出正確的行為,那么就稱這個類是線程安全的。 線程安全性主要體現(xiàn)在三個方面:原子性、可見性...
閱讀 1467·2021-11-22 14:44
閱讀 2847·2021-11-16 11:44
閱讀 3213·2021-10-13 09:40
閱讀 1987·2021-10-08 10:04
閱讀 2368·2021-09-24 10:28
閱讀 2911·2021-09-06 15:02
閱讀 2962·2019-08-30 15:52
閱讀 2397·2019-08-30 13:20