一、鎖的劣勢(shì)
鎖定后如果未釋放询微,再次請(qǐng)求鎖時(shí)會(huì)造成阻塞崖瞭,多線程調(diào)度通常遇到阻塞會(huì)進(jìn)行上下文切換,造成更多的開(kāi)銷拓提。
在掛起與恢復(fù)線程等過(guò)程中存在著很大的開(kāi)銷读恃,并且通常存在著較長(zhǎng)時(shí)間的中斷。
鎖可能導(dǎo)致優(yōu)先級(jí)反轉(zhuǎn)代态,即使較高優(yōu)先級(jí)的線程可以搶先執(zhí)行,但仍然需要等待鎖被釋放疹吃,從而導(dǎo)致它的優(yōu)先級(jí)會(huì)降至低優(yōu)先級(jí)線程的級(jí)別蹦疑。
處理器填寫了一些特殊指令萨驶,例如:比較并交換歉摧、關(guān)聯(lián)加載/條件存儲(chǔ)。
1 比較并交換
CAS的含義是:“我認(rèn)為V的值應(yīng)該為A,如果是叁温,那么將V的值更新為B再悼,否則不需要修改告訴V的值實(shí)際為多少”。CAS是一項(xiàng)樂(lè)觀鎖技術(shù)膝但。
模擬CAS操作例子:
[java]view plaincopy
@?ThreadSafe
publicclassSimulatedCAS?{
@?GuardeBy("this")privateintvalue?;
publicsynchronizedintget(){
returnvalue?;
}
publicsynchronizedintcompareAndSwap(intexpectedValue,intnewValue){
intoldValue?=?value?;
if(oldValue?==?expectedValue)
value?=?newValue;
returnoldValue;
}
publicsynchronizedbooleancompareAndSet(intexpectedValue,intnewValue){
return(expectedValue?==?compareAndSwap(expectedValue,?newValue));
}
}
2 非阻塞的計(jì)數(shù)器
基于CAS實(shí)現(xiàn)的非阻塞計(jì)數(shù)器
[java]view plaincopy
@?ThreadSafe
publicclassCasCounter?{
privateSimulatedCAS?value?;
publicintgetValue(){
returnvalue?.get();
}
publicintincrement(){
intv;
do{
v?=?value?.get();
}while(v?!=?value?.compareAndSwap(v,?v?+1));
returnv?+1;
}
}
CAS的主要缺點(diǎn)是:它將使調(diào)度者處理競(jìng)爭(zhēng)問(wèn)題(通過(guò)重試冲九、回退、放棄)跟束,而在使用鎖中能自動(dòng)處理競(jìng)爭(zhēng)問(wèn)題(線程在獲得鎖之前將一直阻塞)莺奸。
3 JVM對(duì)CAS的支持
[java]view plaincopy
java.util.concurrent.atomic?類的小工具包,支持在單個(gè)變量上解除鎖的線程安全編程冀宴。
AtomicBoolean?可以用原子方式更新的boolean值灭贷。
AtomicInteger?可以用原子方式更新的int值。
AtomicIntegerArray?可以用原子方式更新其元素的int數(shù)組略贮。
AtomicIntegerFieldUpdater?基于反射的實(shí)用工具甚疟,可以對(duì)指定類的指定volatileint字段進(jìn)行原子更新。
AtomicLong?可以用原子方式更新的long值逃延。
AtomicLongArray?可以用原子方式更新其元素的long數(shù)組览妖。
AtomicLongFieldUpdater?基于反射的實(shí)用工具,可以對(duì)指定類的指定volatilelong字段進(jìn)行原子更新真友。
AtomicMarkableReference?AtomicMarkableReference?維護(hù)帶有標(biāo)記位的對(duì)象引用黄痪,可以原子方式對(duì)其進(jìn)行更新。
AtomicReference?可以用原子方式更新的對(duì)象引用盔然。
AtomicReferenceArray?可以用原子方式更新其元素的對(duì)象引用數(shù)組桅打。
AtomicReferenceFieldUpdater?基于反射的實(shí)用工具,可以對(duì)指定類的指定volatile字段進(jìn)行原子更新愈案。
AtomicStampedReference?AtomicStampedReference?維護(hù)帶有整數(shù)“標(biāo)志”的對(duì)象引用挺尾,可以用原子方式對(duì)其進(jìn)行更新。
1 原子變量是一種“更好的volatile”
通過(guò)CAS來(lái)維持包含多個(gè)變量的不變性條件例子:
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
publicclassCasNumberRange?{
privatestaticclassIntPair{
finalintlower?;//?不變性條件:?lower?<=?upper
finalintupper?;
publicIntPair(intlower,intupper)?{
this.lower?=?lower;
this.upper?=?upper;
}
}
privatefinalAtomicReference?values?=
newAtomicReference(newIntPair(0,0));
publicintgetLower(){
returnvalues?.get().?lower;
}
publicintgetUpper(){
returnvalues?.get().?upper;
}
publicvoidsetLower(inti){
while(true){
IntPair?oldv?=?values?.get();
if(i?>?oldv.upper?){
thrownewIllegalArgumentException("Cant't?set?lower?to?"+?i?+"?>?upper");
}
IntPair?newv?=newIntPair(i,?oldv.upper?);
if(values?.compareAndSet(oldv,?newv)){
return;
}
}
}
//?對(duì)setUpper采用類似的方法
}
2 性能比較:鎖與原子變量
使用ReentrantLock遭铺、AtomicInteger、ThreadLocal比較恢准,通常情況下效率排序是ThreadLocal >?AtomicInteger >?ReentrantLock魂挂。
1 非阻塞的棧
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
publicclassConcurrentStack?{
privateAtomicReference>?top?=newAtomicReference>();
publicvoidpush(E?item){
Node?newHead?=newNode(item);
Node?oldHead;
do{
oldHead?=?top?.get();
newHead.?next?=?oldHead;
}while(!top?.compareAndSet(oldHead,?newHead));
}
publicE?pop(){
Node?oldHead;
Node?newHead;
do{
oldHead?=?top?.get();
if(oldHead?==null)?{
returnnull;
}
newHead?=?oldHead.?next?;
}while(!top?.compareAndSet(oldHead,?newHead));
returnoldHead.item?;
}
privatestaticclassNode{
publicfinalE?item;
publicNode?next?;
publicNode(E?item){
this.item?=?item;
}
}
}
2 非阻塞的鏈表
CAS基本使用模式:在更新某個(gè)值時(shí)存在不確定性馁筐,以及在更新失敗時(shí)重新嘗試涂召。
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
@?ThreadSafe
publicclassLinkedQueue?{
privatestaticclassNode{
finalE?item;
finalAtomicReference>?next;
publicNode(E?item,?Node?next){
this.item?=?item;
this.next?=newAtomicReference>(next);
}
}
privatefinalNode?dummy?=newNode(null,null);
privatefinalAtomicReference>?head?=
newAtomicReference>(dummy);
privatefinalAtomicReference>?tail?=
newAtomicReference>(dummy);
publicbooleanput(E?item){
Node?newNode?=newNode(item,null);
while(true){
Node?curTail?=?tail.get();
Node?tailNext?=?curTail.next.get();
if(curTail?==?tail.get()){
if(tailNext?!=null){
//?隊(duì)列處于中間狀態(tài),推進(jìn)尾節(jié)點(diǎn)
tail.compareAndSet(curTail,?tailNext);
}else{
//?處于穩(wěn)定狀態(tài),?嘗試插入新節(jié)點(diǎn)
if(curTail.next.compareAndSet(null,?newNode)){
//?插入操作成功敏沉,嘗試推進(jìn)尾節(jié)點(diǎn)
tail.compareAndSet(curTail,?tailNext);
returntrue;
}
}
}
}
}
}
3 原子的域更新器
原子的域更新器類表示有volatile域的一種基于反射的“視圖”果正,從而能夠在已有的volatile域上使用CAS
[java]view plaincopy
privatestaticclassNode{
privatefinalE?item;
privatevolatileNode?next;
publicNode(E?item){
this.item?=?item;
}
}
privatestaticAtomicReferenceFieldUpdater?nextUpdater
=?AtomicReferenceFieldUpdater.newUpdater(Node.class,?Node.class,"next");
4 ABA問(wèn)題
處理V的值首先由A變成B炎码,再由B變成A的問(wèn)題。
好了同學(xué)們秋泳,我能介紹的也都全部介紹完給你們了潦闲,如果下獲得更多JAVA教學(xué)資源,可以選擇來(lái)我們這里共同交流迫皱,群:240448376歉闰,很多大神在這里切磋學(xué)習(xí),不懂可以直接問(wèn)舍杜,晚上還有大牛免費(fèi)直播教學(xué)新娜。
注:加群要求
1、具有一定工作經(jīng)驗(yàn)的既绩,面對(duì)目前流行的技術(shù)不知從何下手概龄,需要突破技術(shù)瓶頸的可以加,有些應(yīng)屆生和實(shí)習(xí)生也可以加饲握。
2私杜、在公司待久了,過(guò)得很安逸救欧,但跳槽時(shí)面試碰壁衰粹。需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加笆怠。
3铝耻、如果沒(méi)有工作經(jīng)驗(yàn),但基礎(chǔ)非常扎實(shí)蹬刷,對(duì)java工作機(jī)制瓢捉,常用設(shè)計(jì)思想,常用java開(kāi)發(fā)框架掌握熟練的办成,可以加泡态。
4、覺(jué)得自己很牛B迂卢,一般需求都能搞定某弦。但是所學(xué)的知識(shí)點(diǎn)沒(méi)有系統(tǒng)化,很難在技術(shù)領(lǐng)域繼續(xù)突破的可以加而克。
5.阿里Java高級(jí)大牛直播講解知識(shí)點(diǎn)靶壮,分享知識(shí),多年工作經(jīng)驗(yàn)的梳理和總結(jié)员萍,帶著大家全面亮钦、科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知!
PS:現(xiàn)在主要講解的內(nèi)容是(反射原理充活、枚舉原理與應(yīng)用蜂莉、注解原理、常用設(shè)計(jì)模式混卵、正規(guī)表達(dá)式高級(jí)應(yīng)用映穗、JAVA操作Office原理詳解、JAVA圖像處理技術(shù)幕随,等多個(gè)知識(shí)點(diǎn)的詳解和實(shí)戰(zhàn))
6.小號(hào)或者小白之類加群一律不給過(guò)蚁滋,謝謝。
最后赘淮,每一位讀到這里的網(wǎng)友辕录,感謝你們能耐心地看完。覺(jué)得對(duì)你有幫助可以給個(gè)喜歡梢卸!希望在成為一名更優(yōu)秀的Java程序員的道路上走诞,我們可以一起學(xué)習(xí)、一起進(jìn)步