一、鎖的劣勢
鎖定后如果未釋放,再次請(qǐng)求鎖時(shí)會(huì)造成阻塞,多線程調(diào)度通常遇到阻塞會(huì)進(jìn)行上下文切換,造成更多的開銷。
在掛起與恢復(fù)線程等過程中存在著很大的開銷,并且通常存在著較長時(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)樂觀鎖技術(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)度者處理競爭問題(通過重試、回退、放棄),而在使用鎖中能自動(dòng)處理競爭問題(線程在獲得鎖之前將一直阻塞)。
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”
通過CAS來維持包含多個(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問題
處理V的值首先由A變成B,再由B變成A的問題。
好了同學(xué)們,我能介紹的也都全部介紹完給你們了,如果下獲得更多JAVA教學(xué)資源,可以選擇來我們這里共同交流,群:240448376,很多大神在這里切磋學(xué)習(xí),不懂可以直接問,晚上還有大牛免費(fèi)直播教學(xué)。
注:加群要求
1、具有一定工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手,需要突破技術(shù)瓶頸的可以加,有些應(yīng)屆生和實(shí)習(xí)生也可以加。
2、在公司待久了,過得很安逸,但跳槽時(shí)面試碰壁。需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加。
3、如果沒有工作經(jīng)驗(yàn),但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制,常用設(shè)計(jì)思想,常用java開發(fā)框架掌握熟練的,可以加。
4、覺得自己很牛B,一般需求都能搞定。但是所學(xué)的知識(shí)點(diǎn)沒有系統(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)或者小白之類加群一律不給過,謝謝。
最后,每一位讀到這里的網(wǎng)友,感謝你們能耐心地看完。覺得對(duì)你有幫助可以給個(gè)喜歡!希望在成為一名更優(yōu)秀的Java程序員的道路上,我們可以一起學(xué)習(xí)、一起進(jìn)步