自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

 這次我們來看鎖

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

[[277634]]

鎖有什么作用呢?

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

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

Java中的鎖

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

樂觀鎖和悲觀鎖

悲觀鎖

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

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

 

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

 

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

 

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

 

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

樂觀鎖

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

 

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

 

CAS

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

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

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

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

CAS的問題

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

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

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

  • 使用悲觀鎖和樂觀鎖

 

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

 

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

公平鎖和非公平鎖

上面說了悲觀鎖和樂觀鎖,現(xiàn)在來看公平鎖和非公平鎖。在鎖中也是有公平和不公平滴,公平鎖如其名講究的是一個(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ì)的過程中并不會(huì)有人吃不到飯,這個(gè)時(shí)候食堂阿姨是公平的每個(gè)人排隊(duì)的話都能吃到飯,線程也是如此。非公平鎖可以這樣理解,我那個(gè)同學(xué)去食堂排隊(duì)打飯了但是有人卻插隊(duì),食堂阿姨卻不公平直接給插隊(duì)的人打飯卻不給他打,你說氣不氣是不是很不公平,劃重點(diǎn)非公平鎖先到不一定先得。不過公平鎖也是有缺點(diǎn)的,當(dāng)一個(gè)線程獲取資源后在隊(duì)列中的其他的線程就只能在阻塞,CPU的所以公平鎖比非公平鎖的效率要低很多。因?yàn)镃PU喚醒阻塞線程的開銷比非公平鎖大。我們來看一個(gè)一個(gè)例子:

 

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

 

在Java中ReentrantLock提供了公平鎖和非公平鎖的實(shí)現(xiàn)。看一下ReentrantLock怎么實(shí)現(xiàn)公平鎖和非公平鎖

 

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

 

使用公平鎖和非公平鎖

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

 

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

 

公平鎖

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

 

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

 

輸出結(jié)果

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

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

 

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

 

非公平鎖的例子

輸出結(jié)果:

 

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

 

輸出結(jié)果

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

所以在使用公平鎖的時(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ì)帶來性能的開銷。

獨(dú)占鎖和共享鎖

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

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

自旋鎖

什么是自旋鎖,自旋鎖其實(shí)就是當(dāng)一個(gè)線程獲取鎖的時(shí)候,這個(gè)鎖已經(jīng)被其他人獲取到了那么這個(gè)線程不會(huì)立馬掛起,反而在不放棄CPU使用權(quán)的情況下會(huì)嘗試再次獲取鎖資源,默認(rèn)次數(shù)是10次,可以使用-XX: PreBlockSpinsh來設(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é)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2024-01-17 08:18:14

RPAJava技術(shù)

2021-04-16 16:37:23

SpringMVC源碼配置

2015-10-12 17:11:34

老板重構(gòu)系統(tǒng)

2015-11-10 09:17:29

重構(gòu)程序員代碼

2025-03-10 00:17:00

2019-10-16 08:25:33

JavaScriptwebprototype

2021-03-04 09:26:57

微服務(wù)架構(gòu)數(shù)據(jù)

2021-01-04 13:40:59

Git開源工具

2019-06-13 10:24:34

工具性能數(shù)據(jù)

2017-12-12 13:27:20

主板跳線USB

2019-09-11 08:52:24

MVCMVPMVVM

2022-08-09 08:00:55

AWS安全API

2019-01-30 13:44:34

JVM內(nèi)存服務(wù)器

2023-11-01 15:52:35

2021-04-07 13:28:21

函數(shù)程序員異步

2020-07-28 17:27:53

Nginx 負(fù)載均衡模塊

2019-05-30 09:32:49

2020-06-23 16:28:25

Nginx負(fù)載均衡服務(wù)器

2019-12-05 14:24:47

數(shù)字認(rèn)證電子認(rèn)證CA

2018-10-12 09:42:00

分布式鎖 Java多線
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)