成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

悲觀鎖java代碼實(shí)現(xiàn) 悲觀鎖 java

Java鎖有哪些種類,以及區(qū)別

一、公平鎖/非公平鎖

保定ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

公平鎖是指多個(gè)線程按照申請(qǐng)鎖的順序來(lái)獲取鎖。

非公平鎖是指多個(gè)線程獲取鎖的順序并不是按照申請(qǐng)鎖的順序,有可能后申請(qǐng)的線程比先申請(qǐng)的線程優(yōu)先獲取鎖。有可能,會(huì)造成優(yōu)先級(jí)反轉(zhuǎn)或者饑餓現(xiàn)象。

對(duì)于Java ReentrantLock而言,通過(guò)構(gòu)造函數(shù)指定該鎖是否是公平鎖,默認(rèn)是非公平鎖。非公平鎖的優(yōu)點(diǎn)在于吞吐量比公平鎖大。

對(duì)于Synchronized而言,也是一種非公平鎖。由于其并不像ReentrantLock是通過(guò)AQS的來(lái)實(shí)現(xiàn)線程調(diào)度,所以并沒(méi)有任何辦法使其變成公平鎖。

二、可重入鎖

可重入鎖又名遞歸鎖,是指在同一個(gè)線程在外層方法獲取鎖的時(shí)候,在進(jìn)入內(nèi)層方法會(huì)自動(dòng)獲取鎖。說(shuō)的有點(diǎn)抽象,下面會(huì)有一個(gè)代碼的示例。

對(duì)于Java ReentrantLock而言, 他的名字就可以看出是一個(gè)可重入鎖,其名字是Re entrant Lock重新進(jìn)入鎖。

對(duì)于Synchronized而言,也是一個(gè)可重入鎖??芍厝腈i的一個(gè)好處是可一定程度避免死鎖。

synchronized void setA() throws Exception{

Thread.sleep(1000);

setB();

}

synchronized void setB() throws Exception{

Thread.sleep(1000);

}

上面的代碼就是一個(gè)可重入鎖的一個(gè)特點(diǎn),如果不是可重入鎖的話,setB可能不會(huì)被當(dāng)前線程執(zhí)行,可能造成死鎖。

三、獨(dú)享鎖/共享鎖

獨(dú)享鎖是指該鎖一次只能被一個(gè)線程所持有。

共享鎖是指該鎖可被多個(gè)線程所持有。

對(duì)于Java

ReentrantLock而言,其是獨(dú)享鎖。但是對(duì)于Lock的另一個(gè)實(shí)現(xiàn)類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨(dú)享鎖。

讀鎖的共享鎖可保證并發(fā)讀是非常高效的,讀寫,寫讀 ,寫寫的過(guò)程是互斥的。

獨(dú)享鎖與共享鎖也是通過(guò)AQS來(lái)實(shí)現(xiàn)的,通過(guò)實(shí)現(xiàn)不同的方法,來(lái)實(shí)現(xiàn)獨(dú)享或者共享。

對(duì)于Synchronized而言,當(dāng)然是獨(dú)享鎖。

四、互斥鎖/讀寫鎖

上面講的獨(dú)享鎖/共享鎖就是一種廣義的說(shuō)法,互斥鎖/讀寫鎖就是具體的實(shí)現(xiàn)。

互斥鎖在Java中的具體實(shí)現(xiàn)就是ReentrantLock

讀寫鎖在Java中的具體實(shí)現(xiàn)就是ReadWriteLock

五、樂(lè)觀鎖/悲觀鎖

樂(lè)觀鎖與悲觀鎖不是指具體的什么類型的鎖,而是指看待并發(fā)同步的角度。

悲觀鎖認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,一定是會(huì)發(fā)生修改的,哪怕沒(méi)有修改,也會(huì)認(rèn)為修改。因此對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,悲觀鎖采取加鎖的形式。悲觀的認(rèn)為,不加鎖的并發(fā)操作一定會(huì)出問(wèn)題。

樂(lè)觀鎖則認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,是不會(huì)發(fā)生修改的。在更新數(shù)據(jù)的時(shí)候,會(huì)采用嘗試更新,不斷重新的方式更新數(shù)據(jù)。樂(lè)觀的認(rèn)為,不加鎖的并發(fā)操作是沒(méi)有事情的。

從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場(chǎng)景,樂(lè)觀鎖適合讀操作非常多的場(chǎng)景,不加鎖會(huì)帶來(lái)大量的性能提升。

悲觀鎖在Java中的使用,就是利用各種鎖。

樂(lè)觀鎖在Java中的使用,是無(wú)鎖編程,常常采用的是CAS算法,典型的例子就是原子類,通過(guò)CAS自旋實(shí)現(xiàn)原子操作的更新。

六、分段鎖

分段鎖其實(shí)是一種鎖的設(shè)計(jì),并不是具體的一種鎖,對(duì)于ConcurrentHashMap而言,其并發(fā)的實(shí)現(xiàn)就是通過(guò)分段鎖的形式來(lái)實(shí)現(xiàn)高效的并發(fā)操作。

我們以ConcurrentHashMap來(lái)說(shuō)一下分段鎖的含義以及設(shè)計(jì)思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似于HashMap(JDK7與JDK8中HashMap的實(shí)現(xiàn))的結(jié)構(gòu),即內(nèi)部擁有一個(gè)Entry數(shù)組,數(shù)組中的每個(gè)元素又是一個(gè)鏈表;同時(shí)又是一個(gè)ReentrantLock(Segment繼承了ReentrantLock)。

當(dāng)需要put元素的時(shí)候,并不是對(duì)整個(gè)hashmap進(jìn)行加鎖,而是先通過(guò)hashcode來(lái)知道他要放在那一個(gè)分段中,然后對(duì)這個(gè)分段進(jìn)行加鎖,所以當(dāng)多線程put的時(shí)候,只要不是放在一個(gè)分段中,就實(shí)現(xiàn)了真正的并行的插入。

但是,在統(tǒng)計(jì)size的時(shí)候,可就是獲取hashmap全局信息的時(shí)候,就需要獲取所有的分段鎖才能統(tǒng)計(jì)。

分段鎖的設(shè)計(jì)目的是細(xì)化鎖的粒度,當(dāng)操作不需要更新整個(gè)數(shù)組的時(shí)候,就僅僅針對(duì)數(shù)組中的一項(xiàng)進(jìn)行加鎖操作。

七、偏向鎖/輕量級(jí)鎖/重量級(jí)鎖

這三種鎖是指鎖的狀態(tài),并且是針對(duì)Synchronized。在Java

5通過(guò)引入鎖升級(jí)的機(jī)制來(lái)實(shí)現(xiàn)高效Synchronized。這三種鎖的狀態(tài)是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的。

偏向鎖是指一段同步代碼一直被一個(gè)線程所訪問(wèn),那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)。

輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被另一個(gè)線程所訪問(wèn),偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線程會(huì)通過(guò)自旋的形式嘗試獲取鎖,不會(huì)阻塞,提高性能。

重量級(jí)鎖是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候,另一個(gè)線程雖然是自旋,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋一定次數(shù)的時(shí)候,還沒(méi)有獲取到鎖,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖。重量級(jí)鎖會(huì)讓其他申請(qǐng)的線程進(jìn)入阻塞,性能降低。

八、自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的線程不會(huì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會(huì)消耗CPU。

典型的自旋鎖實(shí)現(xiàn)的例子,可以參考自旋鎖的實(shí)現(xiàn)

java中悲觀鎖和樂(lè)觀鎖的區(qū)別

樂(lè)觀鎖和悲觀鎖的區(qū)別如下:

1、悲觀鎖是當(dāng)線程拿到資源時(shí),就對(duì)資源上鎖,并在提交后,才釋放鎖資源,其他線程才能使用資源。

2、樂(lè)觀鎖是當(dāng)線程拿到資源時(shí),上樂(lè)觀鎖,在提交之前,其他的鎖也可以操作這個(gè)資源,當(dāng)有沖突的時(shí)候,并發(fā)機(jī)制會(huì)保留前一個(gè)提交,打回后一個(gè)提交,讓后一個(gè)線程重新獲取資源后,再操作,然后提交。和git上傳代碼一樣,兩個(gè)線程都不是直接獲取資源本身,而是先獲取資源的兩個(gè)copy版本,然后在這兩個(gè)copy版本上修改。

3、悲觀鎖和樂(lè)觀鎖在并發(fā)量低的時(shí)候,性能差不多,但是在并發(fā)量高的時(shí)候,樂(lè)觀鎖的性能遠(yuǎn)遠(yuǎn)優(yōu)于悲觀鎖。

4、常用的synchronized是悲觀鎖,lock是樂(lè)觀鎖。

請(qǐng)問(wèn)一個(gè)悲觀鎖的問(wèn)題,就是在程序中實(shí)現(xiàn)該如何做啊,謝謝

假如要按照你這種 悲觀鎖 的處理機(jī)制的話, 那么

Connection conn 要定義在外面, 也就是類這個(gè)級(jí)別。

例如

public class Test {

Connection conn;

public Product get(id) {

conn = getConn();

conn.startTraction();

...............select * from product where id = 10 for update;

}

public void update(long id) {

// 這個(gè)時(shí)候, 用類一個(gè)級(jí)別的 Conn , 不用新建

update product set name = 'xxx' where id = :id;

// 更新完畢后

Commit 事務(wù)。

關(guān)閉 Conn.

}

}

上面的只是 原理的 例子, 實(shí)際情況下,不推薦這么寫

因?yàn)?如果有人 只 Product get(id) 不 update(long id) 的話, 事情就麻煩了。

Java如何實(shí)現(xiàn)對(duì)Mysql數(shù)據(jù)庫(kù)的行鎖

下面通過(guò)一個(gè)例子來(lái)說(shuō)明

場(chǎng)景如下:

用戶賬戶有余額,當(dāng)發(fā)生交易時(shí),需要實(shí)時(shí)更新余額。這里如果發(fā)生并發(fā)問(wèn)題,那么會(huì)造成用戶余額和實(shí)際交易的不一致,這對(duì)公司和客戶來(lái)說(shuō)都是很危險(xiǎn)的。

那么如何避免:

網(wǎng)上查了下,有以下兩種方法:

1、使用悲觀鎖

當(dāng)需要變更余額時(shí),通過(guò)代碼在事務(wù)中對(duì)當(dāng)前需要更新的記錄設(shè)置for update行鎖,然后開(kāi)始正常的查詢和更新操作

這樣,其他的事務(wù)只能等待該事務(wù)完成后方可操作

當(dāng)然要特別注意,如果使用了Spring的事務(wù)注解,需要配置一下:

!-- (事務(wù)管理)transaction manager, use JtaTransactionManager for global tx --

bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

property name="dataSource" ref="dataSource" /

/bean

!-- 使用annotation定義事務(wù) --

tx:annotation-driven transaction-manager="transactionManager" /

在指定代碼處添加事務(wù)注解

@Transactional

@Override

public boolean increaseBalanceByLock(Long userId, BigDecimal amount)

throws ValidateException {

long time = System.currentTimeMillis();

//獲取對(duì)記錄的鎖定

UserBalance balance = userBalanceDao.getLock(userId);

LOGGER.info("[lock] start. time: {}", time);

if (null == balance) {

throw new ValidateException(

ValidateErrorCode.ERRORCODE_BALANCE_NOTEXIST,

"user balance is not exist");

}

boolean result = userBalanceDao.increaseBalanceByLock(balance, amount);

long timeEnd = System.currentTimeMillis();

LOGGER.info("[lock] end. time: {}", timeEnd);

return result;

}

MyBatis中的鎖定方式,實(shí)際測(cè)試該方法確實(shí)可以有效控制,不過(guò)在大并發(fā)量的情況下,可能會(huì)有性能問(wèn)題吧

select id="getLock" resultMap="BaseResultMap" parameterType="java.lang.Long"

![CDATA[

select * from user_balance where id=#{id,jdbcType=BIGINT} for update;

]]

/select

2、使用樂(lè)觀鎖

這個(gè)方法也同樣可以解決場(chǎng)景中描述的問(wèn)題(我認(rèn)為比較適合并不頻繁的操作):

設(shè)計(jì)表的時(shí)候增加一個(gè)version(版本控制字段),每次需要更新余額的時(shí)候,先獲取對(duì)象,update的時(shí)候根據(jù)version和id為條件去更新,如果更新回來(lái)的數(shù)量為0,說(shuō)明version已經(jīng)變更

需要重復(fù)一次更新操作,如下:sql腳本

update user_balance set Balance = #{balance,jdbcType=DECIMAL},Version = Version+1 where Id = #{id,jdbcType=BIGINT} and Version = #{version,jdbcType=BIGINT}

這是一種不使用數(shù)據(jù)庫(kù)鎖的方法,解決方式也很巧妙。當(dāng)然,在大量并發(fā)的情況下,一次扣款需要重復(fù)多次的操作才能成功,還是有不足之處的。不知道還有沒(méi)有更好的方法。

本文標(biāo)題:悲觀鎖java代碼實(shí)現(xiàn) 悲觀鎖 java
鏈接分享:http://jinyejixie.com/article0/hehdoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、網(wǎng)站營(yíng)銷、網(wǎng)站收錄、網(wǎng)站策劃、外貿(mào)建站、網(wǎng)站維護(hù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)
阿瓦提县| 道真| 建水县| 佛山市| 常宁市| 铁岭县| 襄樊市| 崇信县| 霍城县| 邯郸市| 崇信县| 水富县| 六枝特区| 衢州市| 灌南县| 桐庐县| 铜陵市| 辽源市| 辽阳市| 会东县| 潜山县| 永寿县| 曲松县| 东海县| 宜君县| 铁岭市| 射洪县| 邢台县| 新余市| 永胜县| 维西| 信宜市| 广宗县| 漯河市| 比如县| 阜新市| 兴化市| 龙泉市| 北安市| 滨海县| 阿尔山市|