真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

分布式鎖場(chǎng)景

為振安等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及振安網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、網(wǎng)站制作、振安網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

在分布式環(huán)境下多個(gè)操作需要以原子的方式執(zhí)行

首先啟一個(gè)springboot項(xiàng)目,再引入redis依賴包:

org.springframework.boot

spring-boot-starter-data-redis

2.2.2.RELEASE

以下是一個(gè)扣減庫(kù)存的接口作為例子:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

return "end";

}

}

1.單實(shí)例應(yīng)用場(chǎng)景

以上代碼使用JMeter壓測(cè)工具進(jìn)行調(diào)用,設(shè)置參數(shù)為:

Number Of Threads[users]:100

Ramp Up Period[in seconds]:0

Loop Count:2

用單個(gè)web調(diào)用,結(jié)果出現(xiàn)并發(fā)問題:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

解決方案:加入同步鎖(synchronized)

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

synchronized(this) {

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

return "end";

}

}

}

2.多實(shí)例分布式場(chǎng)景

以上代碼,比如有多個(gè)應(yīng)用程序,用nginx做負(fù)載均衡,進(jìn)行同時(shí)調(diào)用壓測(cè)

兩個(gè)程序存在同樣的扣減,出現(xiàn)并發(fā)現(xiàn)象。

第一個(gè)應(yīng)用扣減結(jié)果顯示:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

第二個(gè)應(yīng)用扣減結(jié)果顯示:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

解決方案:redis的setnx方法(可參考SETNX的api)

多個(gè)線程setnx調(diào)用時(shí),有且僅有一個(gè)線程會(huì)拿到這把鎖,所以拿到鎖的執(zhí)行業(yè)務(wù)代碼,最后釋放掉鎖,代碼如下:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

String lockkey = "lockkey";

Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue");//jedis.setnx

if(!result) {

return "";

}

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

springRedisTemplate.delete(lockkey);

return "end";

}

}

調(diào)用200次,壓測(cè)結(jié)果顯示還是有問題,只減掉了一部分:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

這時(shí),加大壓測(cè)次數(shù),結(jié)果正常了:

第一個(gè)應(yīng)用扣減結(jié)果顯示:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

第二個(gè)應(yīng)用扣減結(jié)果顯示:

Redis實(shí)現(xiàn)高并發(fā)分布式鎖

這個(gè)只是因?yàn)榧哟罅苏{(diào)用次數(shù),執(zhí)行業(yè)務(wù)代碼需要一點(diǎn)時(shí)間,這段時(shí)間拒絕了很多等待獲取鎖的請(qǐng)求。但是,還是有問題,假如redis服務(wù)掛掉了,拋出異常了,這時(shí)鎖不會(huì)被釋放掉,出現(xiàn)死鎖問題,可以添加try catch處理,代碼如下:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

String lockkey = "lockkey";

try{鄭州專業(yè)婦科醫(yī)院 http://fk.zyfuke.com/

Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue");//jedis.setnx

if(!result) {

return "";

}

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

}finally{

springRedisTemplate.delete(lockkey);

}

return "end";

}

}

這時(shí),Redis服務(wù)掛掉導(dǎo)致死鎖的問題解決了,但是,如果服務(wù)器果宕機(jī)了,又會(huì)導(dǎo)致鎖不能被釋放的現(xiàn)象,所以可以設(shè)置超時(shí)時(shí)間為10s,代碼如下:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

String lockkey = "lockkey";

try{

Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue",10,TimeUnit.SECONDS);//jedis.setnx

//Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue");//jedis.setnx

//stringRedisTemplate.expire(lockkey,10,TimeUnit.SECONDS);

if(!result) {

return "";

}

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

}finally{

springRedisTemplate.delete(lockkey);

}

return "end";

}

}

這時(shí),如果有一個(gè)線程執(zhí)行需要15s,當(dāng)執(zhí)行到10s時(shí)第二個(gè)線程進(jìn)來拿到這把鎖,會(huì)出現(xiàn)多個(gè)線程拿到同一把鎖執(zhí)行,在第一個(gè)線程執(zhí)行完時(shí)會(huì)釋放掉第二個(gè)線程的鎖,以此類推…就會(huì)導(dǎo)致鎖的永久失效。所以,只能自己釋放自己的鎖,可以給當(dāng)前線程取一個(gè)名字,代碼如下:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

String lockkey = "lockkey";

String clientId = UUID.randomUUID().toString();

try{

Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,clientId ,10,TimeUnit.SECONDS);//jedis.setnx

//Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue");//jedis.setnx

//stringRedisTemplate.expire(lockkey,10,TimeUnit.SECONDS);

if(!result) {

return "";

}

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

}finally{

springRedisTemplate.delete(lockkey);

}

return "end";

}

}

永久失效的問題解決了,但是,如果第一個(gè)線程執(zhí)行15s,還是會(huì)存在多個(gè)線程擁有同一把鎖的現(xiàn)象。所以,需要續(xù)期超時(shí)時(shí)間,當(dāng)一個(gè)線程執(zhí)行5s后對(duì)超時(shí)時(shí)間進(jìn)行續(xù)期都10s,就可以解決了,續(xù)期設(shè)置可以借助redission工具。

Redission使用

Redission分布式鎖實(shí)現(xiàn)原理

pom.xml

org.redisson

redisson

3.6.5

Application.java啟動(dòng)類

@bean

public Redission redission {

//此為單機(jī)模式

Config config = new Config();

config.useSingleServer().setAddress("redis://120.0.0.1:6379").setDatabase(0);

return (Redission)Redission.creat(config);

}

最終解決以上所有問題的代碼如下:

@RestController

public class IndexController {

@Autowired

private StringRedisTemplate stringRedisTemplate;

@Autowired

private Redissionredission;

@RequestMapping("/deduct_stock")

public Stirng deductStock() {

String lockkey = "lockkey";

//String clientId = UUID.randomUUID().toString();

RLock lock = redission.getLock();

try{

//Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,clientId ,10,TimeUnit.SECONDS);//jedis.setnx

//Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockkey,"lockvalue");//jedis.setnx

//stringRedisTemplate.expire(lockkey,10,TimeUnit.SECONDS);

//加鎖:redission默認(rèn)超時(shí)時(shí)間為30s,每10s續(xù)期一次,也可以自己設(shè)置時(shí)間

lock.lock(60,TimeUnit.SECONDS);

int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));//jedis.get(key)

if (stock > 0) {

int realStock = stock - 1;

stringRedisTemplate.opsForValue.set("stock",realStock+"");//jedis.set(key,value)

System.out.println(扣減成功,剩余庫(kù)存:" + realStock + "");

} else {

System.out.println(扣減失敗,庫(kù)存不足!" );

}

}finally{

lock.unlock();

//springRedisTemplate.delete(lockkey);

}

return "end";

}

}

高并發(fā)分布式鎖的問題得到解決。


網(wǎng)頁(yè)標(biāo)題:Redis實(shí)現(xiàn)高并發(fā)分布式鎖
網(wǎng)站網(wǎng)址:http://weahome.cn/article/gooejj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部