首先,要知道原子性和可見性是在并發(fā)環(huán)境需要思考的問題,所以下面的回答是圍繞了并發(fā)場(chǎng)景來描述的。
曹妃甸ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
如果大家不明白并發(fā)場(chǎng)景,請(qǐng)先了解java并發(fā)
原子性,可以理解為CPU層面不能分割的操作,那么 i++是原子操作嗎?不是的,實(shí)際它是i=i+1,這個(gè)操作首先要讀取i的值,然后為i值加1。是需要拆分的。非原子操作都會(huì)存在線程安全問題,需要我們使用同步技術(shù)(sychronized)來讓它變成一個(gè)原子操作。有好幾種方式實(shí)現(xiàn)一個(gè)原子操作。java提供了 sychronized代碼塊,lock接口(它的實(shí)現(xiàn)重入鎖是比較常用的)。還可以使用原子數(shù)據(jù)結(jié)構(gòu)。AtomicInteger、AtomicLong、AtomicReference等。
可見性??梢岳斫鉃榫€程層面各個(gè)線程之間對(duì)某個(gè)操作是透明的,各個(gè)線程可以及時(shí)知道引用的改變。volatile修飾的變量可以保證可見性,假如,一個(gè)變量只有 1或者0兩種情況。那么volatile修飾之后,就不需要對(duì)這個(gè)變量加同步操作了。強(qiáng)調(diào)一下。volatile不能保證原子性。volatile修飾的整數(shù)i,在多線程下 i++之后,不能得到預(yù)期的值
Java中的原子操作包括:
1)除long和double之外的基本類型的賦值操作
2)所有引用reference的賦值操作
3)java.concurrent.Atomic.* 包中所有類的一切操作
count++不是原子操作,是3個(gè)原子操作組合
1.讀取主存中的count值,賦值給一個(gè)局部成員變量tmp
2.tmp+1
3.將tmp賦值給count
可能會(huì)出現(xiàn)線程1運(yùn)行到第2步的時(shí)候,tmp值為1;這時(shí)CPU調(diào)度切換到線程2執(zhí)行完畢,count值為1;切換到線程1,繼續(xù)執(zhí)行第3步,count被賦值為1------------結(jié)果就是兩個(gè)線程執(zhí)行完畢,count的值只加了1;
還有一點(diǎn)要注意,如果使用AtomicInteger.set(AtomicInteger.get() + 1),會(huì)和上述情況一樣有并發(fā)問題,要使用AtomicInteger.getAndIncrement()才可以避免并發(fā)問題
不能被分開操作的一段代碼,就叫原子對(duì)象。。
比如,你在atm取款機(jī)取錢,atm程序中吐錢跟在你賬戶上扣掉等額的數(shù)目就是一個(gè)原子性的操作,這兩個(gè)動(dòng)作一定要連在一起操作,要么都成功,要么都失敗,不可以被分開只執(zhí)行某一部分。
像這樣的操作,我們叫它原子操作。
吐錢跟賬戶上扣錢這兩個(gè)行為對(duì)象是嚴(yán)格合為一體的,不可以被分開,我們稱這樣的對(duì)象為原子對(duì)象