創(chuàng)新互聯(lián)www.cdcxhl.cn八線動態(tài)BGP香港云服務器提供商,新人活動買多久送多久,劃算不套路!
創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站建設、網(wǎng)站重做改版、江津網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5開發(fā)、商城網(wǎng)站建設、集團公司官網(wǎng)建設、外貿(mào)網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為江津等各大城市提供網(wǎng)站開發(fā)制作服務。在Java項目中如何使用變量Volatile?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
Java Volatile 詳解
概要:
Java 語言中的 Volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,并且運行時開銷也較少,但是它所能實現(xiàn)的功能也僅是 synchronized 的一部分。本文介紹了幾種有效使用 volatile 變量的模式,并強調(diào)了幾種不適合使用 volatile 變量的情形。
鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility)。互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現(xiàn)對共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個線程能夠使用該共享數(shù)據(jù)??梢娦砸訌碗s一些,它必須確保釋放鎖之前對共享數(shù)據(jù)做出的更改對于隨后獲得該鎖的另一個線程是可見的 —— 如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴重問題。
Volatile 變量
Volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發(fā)現(xiàn) volatile 變量的最新值。Volatile 變量可用于提供線程安全,但是只能應用于非常有限的一組用例:多個變量之間或者某個變量的當前值與修改后值之間沒有約束。因此,單獨使用 volatile 還不足以實現(xiàn)計數(shù)器、互斥鎖或任何具有與多個變量相關的不變式(Invariants)的類(例如 “start <=end”)。
出于簡易性或可伸縮性的考慮,您可能傾向于使用 volatile 變量而不是鎖。當使用 volatile 變量而非鎖時,某些習慣用法(idiom)更加易于編碼和閱讀。此外,volatile 變量不會像鎖那樣造成線程阻塞,因此也很少造成可伸縮性問題。在某些情況下,如果讀操作遠遠大于寫操作,volatile 變量還可以提供優(yōu)于鎖的性能優(yōu)勢。
正確使用 volatile 變量的條件
您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:
對變量的寫操作不依賴于當前值。
該變量沒有包含在具有其他變量的不變式中。
實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立于任何程序的狀態(tài),包括變量的當前狀態(tài)。
第一個條件的限制使 volatile 變量不能用作線程安全計數(shù)器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀?。薷模瓕懭氩僮餍蛄薪M成的組合操作,必須以原子方式執(zhí)行,而 volatile 不能提供必須的原子特性。實現(xiàn)正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現(xiàn)這點。(然而,如果將值調(diào)整為只從單個線程寫入,那么可以忽略第一個條件。)
大多數(shù)編程情形都會與這兩個條件的其中之一沖突,使得 volatile 變量不能像 synchronized 那樣普遍適用于實現(xiàn)線程安全。清單 1 顯示了一個非線程安全的數(shù)值范圍類。它包含了一個不變式 —— 下界總是小于或等于上界。
清單 1. 非線程安全的數(shù)值范圍類
@NotThreadSafe public class NumberRange { private int lower, upper; public int getLower() { return lower; } public int getUpper() { return upper; } public void setLower(int value) { if (value > upper) throw new IllegalArgumentException(...); lower = value; } public void setUpper(int value) { if (value < lower) throw new IllegalArgumentException(...); upper = value; } }