java volatile案例講解
本篇來自java并發(fā)編程實(shí)戰(zhàn)關(guān)于volatile的總結(jié)。
要說volatile,先得明白內(nèi)存可見性。那我們就從內(nèi)存可見性說起。
一、內(nèi)存可見性
可見性是一種復(fù)雜的屬性,因?yàn)榭梢娦灾械腻e誤總是會違背我們的直覺。在單線程環(huán)境中,如果向某個變量先寫入值,然后在沒有其他寫入操作的情況下讀取這個變量,那么總能得到相同的值。這看起來很自然。然而,當(dāng)讀操作和寫操作在不同的線程中執(zhí)行時,情況卻并非如此,這聽起來或許有些難以接受。通常,我們無法確保執(zhí)行讀操作的線程能適時地看到其他線程寫入的值,有時甚至是根本不可能的事情。為了確保多個想成之間對內(nèi)存寫入操作的可見性,必須使用同步機(jī)制。 對于以下代碼:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread{
public void run(){
while(!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args){
new ReaderThread().start();
number = 42;
ready = true;
}
}
NoVisibility可能會持續(xù)循環(huán)下去,因?yàn)樽x線程可能永遠(yuǎn)都看不到ready的值。一種更奇怪的現(xiàn)象是,Novisibility可能會輸出0,因?yàn)樽x線程可能看到了寫入ready的值,但卻沒有看到之后寫入number的值,這種現(xiàn)象被稱為“重排序(Reordering)“。只要在某個線程中無法檢測到重排序情況,(即使在其他線程中可以很明顯地看到該線程中的重排序),那么就無法確保線程中的操作將按照程序中指定的順序來執(zhí)行。當(dāng)主線程首先寫入number,然后在沒有同步的情況下寫入ready,那么讀線程看到的順序可能與寫入的順序完全相反。
在沒有同步的情況下,編譯器、處理器以及運(yùn)行時等都可能對操作的執(zhí)行順序進(jìn)行一些意想不到的調(diào)整。在缺乏足夠同步的多線程程序中,要相對內(nèi)存操作的執(zhí)行順序進(jìn)行判斷,幾乎無法得出正確的結(jié)論。
這看上去似乎是一種失敗的設(shè)計(jì),但卻能使JVM充分地利用現(xiàn)代多核處理器的強(qiáng)大性能。例如,在缺少同步的情況下,java內(nèi)存模型允許編譯器對操作順序進(jìn)行重排序,并將數(shù)值緩存在寄存器中。此外,它還允許CPU對操作順序進(jìn)行重排序,并將數(shù)值環(huán)迅在處理器特定的緩存中。
二、Volatile變量
java語言提供了一種稍弱的同步機(jī)制,即volatile變量,用來確保將變量的更新操作通知到其他線程。當(dāng)把變量聲明為volatile類型后,編譯器與運(yùn)行時都會注意到這個變量是共享的,因此不會將該變量上的操作和其他內(nèi)存操作一起重排序。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。
volatile與加鎖機(jī)制的區(qū)別:
加鎖機(jī)制既可以確??梢娦杂挚梢源_保原子性,而volatile變量只能確??梢娦?。
當(dāng)且僅當(dāng)滿足以下所有條件時,才應(yīng)該使用volatile變量:
- 對變量的寫入操作不依賴變量的當(dāng)前值,或者你能確保只有單個線程更新變量的值。
- 該變量不會與其他狀態(tài)變量一起納入不變性條件中。
- 在訪問變量時不需要加鎖。
到此這篇關(guān)于java volatile案例講解的文章就介紹到這了,更多相關(guān)Java volatile內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項(xiàng)目為何引入大量的starter?如何自定義starter?
這篇文章主要介紹了SpringBoot項(xiàng)目為何引入大量的starter?如何自定義starter?文章基于這兩個問題展開全文,需要的小伙伴可以參考一下2022-04-04
Java實(shí)現(xiàn)添加條形碼到PDF表格的方法詳解
條碼的應(yīng)用已深入生活和工作的方方面面。本文以操作PDF文件為例,介紹如何利用Java語言在編輯表格時,向單元格中添加條形碼,感興趣的可以學(xué)習(xí)一下2022-06-06
Java?Servlet實(shí)現(xiàn)表白墻的代碼實(shí)例
最近用Servlet做了個小項(xiàng)目,分享給大家,下面這篇文章主要給大家介紹了關(guān)于Java?Servlet實(shí)現(xiàn)表白墻的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
SpringBoot生成Excel文件的實(shí)現(xiàn)示例
本文介紹了Spring Boot項(xiàng)目中生成Excel文件,使用了Apache POI庫,包括poi和poi-ooxml依賴,通過遍歷用戶信息列表,將數(shù)據(jù)寫入Excel文件,感興趣的可以了解一下2025-02-02
SpringBoot如何接收前端傳來的json數(shù)據(jù)
這篇文章主要介紹了SpringBoot如何接收前端傳來的json數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)
XMLType是Oracle支持的一種基于XML格式存儲的數(shù)據(jù)類型,這里我們共同來探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)的方法:2016-07-07
Java設(shè)置請求響應(yīng)時間的多種實(shí)現(xiàn)方式
在前后端分離的開發(fā)模式中,前端請求后端獲取數(shù)據(jù)時,合理設(shè)置響應(yīng)時間(超時時間)是提升系統(tǒng)性能和用戶體驗(yàn)的關(guān)鍵,本文將深入探討如何在Java中設(shè)置請求的響應(yīng)時間,需要的朋友可以參考下2025-01-01
Spring的UnsatisfiedDependencyException異常的解決
在使用Spring框架開發(fā)應(yīng)用程序時,我們經(jīng)常會遇到各種異常,本文主要介紹了Spring的UnsatisfiedDependencyException異常的解決,感興趣的可以了解一下2023-11-11

