亚洲全黄无码一级在线看_国产剧情久久久性色_无码av一区二区三区无码_亚洲成a×人片在线观看

當(dāng)前位置: 首頁(yè) > 科技新聞 >

Java中各種鎖讓人頭大,我想要用這篇文章讓你思

時(shí)間:2019-11-12 21:08來(lái)源:網(wǎng)絡(luò)整理 瀏覽:
這次我們來(lái)看鎖 說(shuō)到了鎖我們經(jīng)常會(huì)聯(lián)想到生活中的鎖,在我們?nèi)粘V形覀兘?jīng)常會(huì)接觸到鎖。比如我們的手機(jī)鎖,電腦鎖,再比如我們生活中的門鎖,這些都

這次我們來(lái)看鎖

說(shuō)到了鎖我們經(jīng)常會(huì)聯(lián)想到生活中的鎖,在我們?nèi)粘V形覀兘?jīng)常會(huì)接觸到鎖。比如我們的手機(jī)鎖,電腦鎖,再比如我們生活中的門鎖,這些都是鎖。

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

鎖有什么作用呢?

說(shuō)了這么多還是不清楚鎖到底有什么用處?這一點(diǎn)就要深思我們?yōu)槭裁匆褂面i,我們用手機(jī)鎖是為了保障我們的隱私安全,使用門鎖是為了保障我們的財(cái)產(chǎn)安全,準(zhǔn)確的來(lái)說(shuō)我們使用鎖就是為了安全。

那么在生活中我們可以加鎖來(lái)保障自己的隱私和財(cái)產(chǎn)安全,那Java中的鎖有什么用處呢?

Java中的鎖

Java中的鎖準(zhǔn)確的來(lái)說(shuō)也是為了保證安全,不過(guò)不同的是Java中的鎖是為了保證并發(fā)所需要的。所以在Java中加鎖準(zhǔn)確的來(lái)說(shuō)是為了保證并發(fā)安全,同時(shí)也是為了解決內(nèi)存中的一致性,原子性,有序性三種問(wèn)題。在Java中提供了各式各樣的鎖,每種鎖都有其自身的特點(diǎn)和適用范圍。所以我們都要熟悉鎖的區(qū)別和原理才能正確的使用。

樂(lè)觀鎖和悲觀鎖

悲觀鎖

樂(lè)觀鎖和悲觀鎖的話在之前我剛剛開始寫的時(shí)候就寫過(guò)相關(guān)的文章,在這里就重新介紹一下吧。

悲觀鎖如其名它是悲觀的,它覺(jué)得每次訪問(wèn)數(shù)據(jù)都可能被其他人(線程)修改,所以在訪問(wèn)資源的時(shí)候就會(huì)對(duì)資源進(jìn)行加鎖,用這種方式來(lái)保證資源在訪問(wèn)的時(shí)候不會(huì)被其他線程修改。這樣的話其他線程想要獲取資源的話就只能阻塞,等到當(dāng)前線程釋放鎖后在獲取。在Java中悲觀鎖的實(shí)現(xiàn)有synchronized關(guān)鍵字和Lock的實(shí)現(xiàn)類都是悲觀鎖。我們來(lái)看一下悲觀鎖到底是怎么執(zhí)行的。

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

線程A搶占到資源后線程B就陷入了阻塞中,然后就等待線程A釋放資源。

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

當(dāng)線程A釋放完資源后線程B就去獲取鎖開始操作資源˛悲觀鎖保證了資源同時(shí)只能一個(gè)線程進(jìn)行操作。

樂(lè)觀鎖

與悲觀鎖相反,樂(lè)觀鎖并不會(huì)覺(jué)得訪問(wèn)數(shù)據(jù)的時(shí)候會(huì)有人修改(所以它是樂(lè)觀的),所以在訪問(wèn)資源的時(shí)候并不會(huì)上鎖,但是在提交的時(shí)候回去判斷一下是否有人修改了當(dāng)前數(shù)據(jù),在數(shù)據(jù)庫(kù)中我們可以使用version版本號(hào)去實(shí)現(xiàn)。在Java中我們是使用CSA來(lái)實(shí)現(xiàn)。我們看一下樂(lè)觀鎖的執(zhí)行過(guò)程

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

CAS

CAS(Compare And Swap)算法是一種無(wú)鎖算法,是Java提供的非阻塞原子性操作。在不使用鎖的情況下實(shí)現(xiàn)多線程下的同步。在并發(fā)包中(java.util.concurrent)原子性類都是使用CAS來(lái)實(shí)現(xiàn)樂(lè)觀鎖的。CAS通過(guò)硬件保證了比較更新的原子性,在JDK中Unsafe提供了一系列的compareAndSwap*方法,這里就不深究Unsafe這個(gè)類了。

CAS操作過(guò)程就是將內(nèi)存中的將要被修改的數(shù)據(jù)與預(yù)期的值進(jìn)行比較,如果這兩個(gè)值相等就修改值為新值,否則就不做操作也就是說(shuō)CAS需要三個(gè)操作值:

  • 預(yù)期值的 A
  • 內(nèi)存中的V
  • 將要修改的B

簡(jiǎn)單的來(lái)說(shuō)CAS就是一個(gè)死循環(huán),在循環(huán)中判斷預(yù)期的值和內(nèi)存中的值是否相等,如果相等的話就執(zhí)行修改,如果如果不相等的話就繼續(xù)循環(huán),直到執(zhí)行成功后退出。

CAS的問(wèn)題

  • CAS雖然很牛逼但是它也存在一些問(wèn)題比如ABA問(wèn)題,舉個(gè)例子,現(xiàn)在有內(nèi)存中有一個(gè)共享變量X的值為A,這個(gè)時(shí)候出現(xiàn)一個(gè)變量想要去修改變量X的值,首先會(huì)獲取X的值這個(gè)時(shí)候獲取的是A,然后使用CAS操作把X變量修改成B。這樣看起來(lái)是沒(méi)有問(wèn)題,那如果在線程1獲取變量X之后,執(zhí)行CAS之前出現(xiàn)一個(gè)線程2把X的值修改成B然后CAS操作執(zhí)行又修改成了了A,雖然最后執(zhí)行的結(jié)果共享變量的值為A但是此A已經(jīng)不是線程1獲取的A了。
  • 這就是經(jīng)典的ABA問(wèn)題。產(chǎn)生ABA問(wèn)題是因?yàn)樽兞康臓顟B(tài)值發(fā)生了環(huán)形轉(zhuǎn)換,A可以到B,B可以到A,如果A到B,B到C就不會(huì)發(fā)生這種問(wèn)題。

解決辦法:在JDK1.5后加入了AtomicStampedReference方法給每個(gè)變量加入了一個(gè)時(shí)間戳來(lái)避免ABA問(wèn)題。

同時(shí)CAS還有循環(huán)開銷大的問(wèn)題,因?yàn)闀?huì)一直循環(huán)直到預(yù)期和內(nèi)存相等修改成功。同時(shí)還有只能保證一個(gè)共享變量的原子性的問(wèn)題不過(guò)在JDK1.5之后加入了AtomicReference類來(lái)保證引用對(duì)象之間的原子性。

  • 使用悲觀鎖和樂(lè)觀鎖
Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

可以使用synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)悲觀鎖,樂(lè)觀鎖可以使用并法包下提供的原子類。

公平鎖和非公平鎖

上面說(shuō)了悲觀鎖和樂(lè)觀鎖,現(xiàn)在來(lái)看公平鎖和非公平鎖。在鎖中也是有公平和不公平滴,公平鎖如其名講究的是一個(gè)公平,所以多個(gè)線程同時(shí)申請(qǐng)申請(qǐng)鎖的話,線程會(huì)放入一個(gè)隊(duì)列中,在隊(duì)列中第一個(gè)進(jìn)入隊(duì)列的線程才能獲取鎖資源,講究的是先到先得。就比如我們?cè)趯W(xué)校食堂打飯的時(shí)候,那個(gè)時(shí)候記得我同學(xué)一放學(xué)就趕快去食堂排隊(duì)這樣的話才能盡快的打上飯,而且在排隊(duì)的過(guò)程中并不會(huì)有人吃不到飯,這個(gè)時(shí)候食堂阿姨是公平的每個(gè)人排隊(duì)的話都能吃到飯,線程也是如此。非公平鎖可以這樣理解,我那個(gè)同學(xué)去食堂排隊(duì)打飯了但是有人卻插隊(duì),食堂阿姨卻不公平直接給插隊(duì)的人打飯卻不給他打,你說(shuō)氣不氣是不是很不公平,劃重點(diǎn)非公平鎖先到不一定先得。不過(guò)公平鎖也是有缺點(diǎn)的,當(dāng)一個(gè)線程獲取資源后在隊(duì)列中的其他的線程就只能在阻塞,CPU的所以公平鎖比非公平鎖的效率要低很多。因?yàn)镃PU喚醒阻塞線程的開銷比非公平鎖大。我們來(lái)看一個(gè)一個(gè)例子:

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

在Java中ReentrantLock提供了公平鎖和非公平鎖的實(shí)現(xiàn)??匆幌翿eentrantLock怎么實(shí)現(xiàn)公平鎖和非公平鎖

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

使用公平鎖和非公平鎖

ReentrantLock默認(rèn)就是非公平的鎖,我們來(lái)看一下公平鎖的例子:

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

公平鎖

看一下輸出結(jié)果:

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

輸出結(jié)果

我們可以看到公平鎖的輸出結(jié)果是按照順序來(lái)的,先到先得。

在看一下非公平鎖的例子:

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

非公平鎖的例子

輸出結(jié)果:

Java中各種鎖讓人頭大,我想要用這篇文章讓你思緒清晰

輸出結(jié)果

我們可以看到如果使用非公平鎖的話最后輸出的結(jié)果是完全沒(méi)有順序的,先到不一定先得。

所以在使用公平鎖的時(shí)候線程1獲取到鎖之后線程2在請(qǐng)求鎖的話就會(huì)掛起等待線程1釋放鎖,然后線程2才能獲取鎖。如果再有一個(gè)線程3想要請(qǐng)求鎖的話,這時(shí)候如果使用的是非公平鎖,那么線程2和線程3中兩個(gè)有一個(gè)會(huì)獲取到鎖,公平鎖的情況下線程3只能先掛起,等待線程2獲取鎖資源釋放后在獲取。

什么時(shí)候使用公平鎖和非公平鎖

在需要公平資源的場(chǎng)景下使用公平鎖,如果不需要特殊的公平對(duì)待的話盡量使用非公平鎖,因?yàn)楣芥i會(huì)帶來(lái)性能的開銷。

獨(dú)占鎖和共享鎖

看到獨(dú)占和共享會(huì)聯(lián)想到什么,對(duì)的獨(dú)占鎖就是每次只有一個(gè)線程能霸占這個(gè)鎖資源,而其他線程就只能等待當(dāng)前獲取鎖資源的線程釋放鎖才能再次獲取鎖,剛剛上面的ReentrantLock就是獨(dú)占鎖,那這樣看來(lái)獨(dú)占鎖不也就是悲觀鎖嗎?因?yàn)楸^鎖搶占資源后就只能等待釋放其他線程才能再次獲取到鎖資源。其實(shí)準(zhǔn)確的說(shuō)獨(dú)占鎖也是悲觀鎖。

在談共享鎖,共享鎖其實(shí)也是樂(lè)觀鎖它放寬了鎖的策略允許多個(gè)線程同時(shí)獲取鎖。在并發(fā)包中ReadWriteLock就是一個(gè)典型的共享鎖。它允許一個(gè)資源可以被多個(gè)讀操作訪問(wèn),或者被一個(gè) 寫操作訪問(wèn),但兩者不能同時(shí)進(jìn)行。

自旋鎖

什么是自旋鎖,自旋鎖其實(shí)就是當(dāng)一個(gè)線程獲取鎖的時(shí)候,這個(gè)鎖已經(jīng)被其他人獲取到了那么這個(gè)線程不會(huì)立馬掛起,反而在不放棄CPU使用權(quán)的情況下會(huì)嘗試再次獲取鎖資源,默認(rèn)次數(shù)是10次,可以使用-XX: PreBlockSpinsh來(lái)設(shè)置次數(shù)。如果自旋鎖獲取鎖的時(shí)間太長(zhǎng),會(huì)造成后面的線程CPU資源耗盡釋放。并且自旋鎖是不公平的。

優(yōu)點(diǎn)

自旋鎖不會(huì)使線程狀態(tài)發(fā)生切換,一直處于用戶態(tài),即線程一直都是active的;不會(huì)使線程進(jìn)入阻塞狀態(tài),減少了不必要的上下文切換,執(zhí)行速度快。

【責(zé)任編輯:武曉燕 TEL:(010)68476606】
推薦內(nèi)容