這篇文章主要介紹了Java內(nèi)存模型原子性原理的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)建站致力于網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計,成都網(wǎng)站設(shè)計,集團網(wǎng)站建設(shè)等服務(wù)標(biāo)準(zhǔn)化,推過標(biāo)準(zhǔn)化降低中小企業(yè)的建站的成本,并持續(xù)提升建站的定制化服務(wù)水平進(jìn)行質(zhì)量交付,讓企業(yè)網(wǎng)站從市場競爭中脫穎而出。 選擇創(chuàng)新互聯(lián)建站,就選擇了安全、穩(wěn)定、美觀的網(wǎng)站建設(shè)服務(wù)!原子性問題
原子性是指:一個或多個操作,要么全部執(zhí)行且在執(zhí)行過程中不被任何因素打斷,要么全部不執(zhí)行。
下面就是一段會出現(xiàn)原子性問題的代碼:
public class AtomicProblem { private static Logger logger = LoggerFactory.getLogger(AtomicProblem.class); public static final int THREAD_COUNT = 10; public static void main(String[] args) throws Exception { BankAccount sharedAccount = new BankAccount("account-csx",0.00); ArrayListthreads = new ArrayList<>(); for (int i = 0; i < THREAD_COUNT; i++) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 1000 ; j++) { sharedAccount.deposit(10.00); } } }); thread.start(); threads.add(thread); } for (Thread thread : threads) { thread.join(); } logger.info("the balance is:{}",sharedAccount.getBalance()); } public static class BankAccount { private String accountName; public double getBalance() { return balance; } private double balance; public BankAccount(String accountName, double balance){ this.accountName = accountName; this.balance =balance; } public double deposit(double amount){ balance = balance + amount; return balance; } public double withdraw(double amount){ balance = balance - amount; return balance; } public String getAccountName() { return accountName; } public void setAccountName(String accountName) { this.accountName = accountName; } } }
上面的代碼中開啟了10個線程,每個線程會對共享的銀行賬戶進(jìn)行1000次存款操作,每次存款10塊,所以理論上最后銀行賬戶中的錢應(yīng)該是10 * 1000 * 10 = 100000塊。我執(zhí)行了多次上面的代碼,很多次最后的結(jié)果的確是100000,但是也有幾次的結(jié)果并不是我們預(yù)期的。
14:40:25.981 [main] INFO com.csx.demo.spring.boot.concurrent.jmm.AtomicProblem - the balance is:98260.0
出現(xiàn)上面結(jié)果的原因就是因為下面的操作并不是原子操作,其中的balance是一個共享變量。在多線程環(huán)境下可能會被打斷。
balance = balance + amount;
上面的賦值操作被分為多步執(zhí)行完成,下面簡單解析下兩個線程對balance同時加10的過程(模擬存款過程,假設(shè)balance的初始值還是0)
線程1從共享內(nèi)存中加載balance的初始值0到工作內(nèi)存 線程1對工作內(nèi)存中的值加10 //此時線程1的CPU時間耗盡,線程2獲得執(zhí)行機會 線程2從共享內(nèi)存中加載balance的初始值到工作內(nèi)存,此時balance的值還是0 線程2對工作內(nèi)存中的值加10,此時線程2工作內(nèi)存中的副本值是10 線程2將balance的副本值刷新回共享內(nèi)存,此時共享內(nèi)存中balance的值是10 //線程2CPU時間片耗盡,線程1又獲得執(zhí)行機會 線程1將工作內(nèi)存中的副本值刷新回共享內(nèi)存,但是此時副本的值還是10,所以最后共享內(nèi)存中的值也是10
上面簡單模擬了一個原子性問題導(dǎo)致程序最終結(jié)果出錯的過程。
JMM對原子性問題的保證
自帶原子性保證
在Java中,對基本數(shù)據(jù)類型的變量的讀取和賦值操作是原子性操作。
a = true; //原子性 a = 5; //原子性 a = b; //非原子性,分兩步完成,第一步加載b的值,第二步將b賦值給a a = b + 2; //非原子性,分三步完成 a ++; //非原子性,分三步完成
synchronized
synchronized可以保證操作結(jié)果的原子性。synchronized保證原子性的原理也很簡單,因為synchronized可以防止多個線程并發(fā)執(zhí)行一段代碼。還是用上面存款的場景做列子,我們只需要將存款的方法設(shè)置成synchronized的就能保證原子性了。
public synchronized double deposit(double amount){ balance = balance + amount; //1 return balance; }
加了synchronized后,當(dāng)一個線程沒執(zhí)行完deposit這個方法前,其他線程是不能執(zhí)行這段代碼的。其實我們發(fā)現(xiàn)synchronized并不能將上面的代碼1編程原子性操作,上面的代碼1還是有可能被中斷的,但是即使被中斷了其他線程也不能訪問共享變量balance,當(dāng)之前被中斷的線程繼續(xù)執(zhí)行時得到的結(jié)果還是正確的。
因此synchronized對原子性問題的保證是從最終結(jié)果上來保證的,也就是說它只保證最終的結(jié)果正確,中間操作的是否被打斷沒法保證。這個和CAS操作需要對比著看。
Lock鎖
public double deposit(double amount) { readWriteLock.writeLock().lock(); try { balance = balance + amount; return balance; } finally { readWriteLock.writeLock().unlock(); } }
Lock鎖保證原子性的原理和synchronized類似,這邊不進(jìn)行贅述了。
原子操作類型
public static class BankAccount { //省略其他代碼 private AtomicDouble balance; public double deposit(double amount) { return balance.addAndGet(amount); } //省略其他代碼 }
JDK提供了很多原子操作類來保證操作的原子性。原子操作類的底層是使用CAS機制的,這個機制對原子性的保證和synchronized有本質(zhì)的區(qū)別。CAS機制保證了整個賦值操作是原子的不能被打斷的,而synchronized值能保證代碼最后執(zhí)行結(jié)果的正確性,也就是說synchronized能消除原子性問題對代碼最后執(zhí)行結(jié)果的影響。
簡單總結(jié)
在多線程編程環(huán)境下(無論是多核CPU還是單核CPU),對共享變量的訪問存在原子性問題。這個問題可能會導(dǎo)致程序錯誤的執(zhí)行結(jié)果。JMM主要提供了如下的方式來保證操作的原子,保證程序不受原子性問題的影響。
synchronized機制:保證程序最終正確性,是的程序不受原子性問題的影響;
Lock接口:和synchronized類似;
原子操作類:底層使用CAS機制,能保證操作真正的原子性。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Java內(nèi)存模型原子性原理的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián)建站,關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.cdcxhl.com,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。