redis分布式锁java代码_基于redis实现分布式锁
“?在上一篇文章中介紹了動態(tài)配置定時任務(wù),其中的原理跟spring 定時任務(wù)注解@Scheduled一樣的,都是通過線程池和定義執(zhí)行時間來控制。來思考一個問題,如果我們的定時任務(wù)在分布式微服務(wù)里面呢?在分布式微服務(wù)里面一個微服務(wù)肯定可以有多個實例的,在上一篇文章當(dāng)中配置的定時任務(wù)就會有可能存在多個,顯然定時任務(wù)被多次執(zhí)行并不是我們想要的結(jié)果,這個時候我們的分布式鎖機(jī)制就出現(xiàn)了!”
(分布式鎖有很多實現(xiàn)方式,以前我們都是使用synchronized來處理并發(fā)請求,雖然也支持分布式,但是總有一些業(yè)務(wù)不適合,比如秒殺系統(tǒng)的多個商品同時開啟秒殺,同一時刻只能完成一件商品的減庫存操作,這樣就造成了系統(tǒng)的性能瓶頸,也不符合秒殺系統(tǒng)的設(shè)計思想。由于 synchronized 無法做到細(xì)粒度的控制,從而引進(jìn)了分布式鎖,分布式鎖能夠完成 synchronized 無法做到的點。下面我們要介紹的是基于redis的實現(xiàn)方式)。
01
—
引入redis依賴
引入springboot官方的redis依賴。
引入一個hutool工具包的依賴,功能很全的一個java工具包,強(qiáng)烈推薦使用。
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-data-redisartifactId>dependency><dependency> <groupId>cn.hutoolgroupId> <artifactId>hutool-allartifactId> <version>5.3.2version>dependency>02
—
基于redis實現(xiàn)
怎么使用redis實現(xiàn)呢,先來看下redis的兩個命令。
setnx:如果key不存在就跟set一樣的作用,如果key存在則什么都不做
getandset:返回上一次的value,并設(shè)置新的value
import cn.hutool.core.util.StrUtil;import cn.hutool.log.StaticLog;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;/** * redis分布式鎖 * * @author zhongxiaojian * @date 2020/4/17 **/@Componentpublic class LockUtil { @Autowired private StringRedisTemplate redisTemplate; /** * 加鎖 * * @param key 主鍵 * @param value 當(dāng)前時間+超時時間 * @return true or false */ public boolean lock(String key, String value) { Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, value); if (lock != null && lock) { return true; } String currentValue = redisTemplate.opsForValue().get(key); //如果鎖過期 if (!StrUtil.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) { String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if (StrUtil.isBlank(oldValue) || (!StrUtil.isEmpty(oldValue) && oldValue.equals(currentValue))) { return true; } } return false; } /** * 解鎖 * * @param key 主鍵 * @param value 當(dāng)前時間+超時時間 */ public void unlock(String key, String value) { try { String currentValue = redisTemplate.opsForValue().get(key); if (!StrUtil.isEmpty(currentValue) && currentValue.equals(value)) { redisTemplate.opsForValue().getOperations().delete(key); } } catch (Exception e) { StaticLog.error("redis分布式鎖解鎖異常,{}", e.getMessage()); } }}在上一篇文章當(dāng)中的代碼中使用
public class ScheduleTask implements Runnable { private static final int TIMEOUT = 30000; private String id; private TaskService service; private String keyword; private LockUtil lockUtil; public String getId() { return id; } /** * @param id 任務(wù)ID * @param service 業(yè)務(wù)類 * @param keyword 關(guān)鍵字參數(shù) */ public ScheduleTask(String id, TaskService service,LockUtil lockUtil, String keyword) { this.id = id; this.service = service; this.lockUtil = lockUtil; this.keyword = keyword; } @Override public void run() { String currentTime = DateUtil.now(); long time = System.currentTimeMillis() + TIMEOUT; if (lockUtil.lock(id, String.valueOf(time))) { System.out.println("ScheduleTask start taskId: " + this.id + " time: " + currentTime); try { service.work(keyword); } catch (Exception e) { StaticLog.error(e.getMessage()); } finally { lockUtil.unlock(id, String.valueOf(time)); } } }}03
—
秒殺系統(tǒng)下的應(yīng)用
這里我們來解釋一下為何在lock方法當(dāng)中加上 “//如果鎖過期” 后面的代碼,我們以商品秒殺系統(tǒng)舉例比較好理解。
假如我們不加上這段代碼,在加鎖之后的業(yè)務(wù)流程拋出了一個異常,且這個異常我們沒有捕獲并處理,那么我們接下來的解鎖操作是不會執(zhí)行的,這個時候我們的鎖就變成了死鎖,我們就可以使用getandset命令來進(jìn)行解鎖,舉個?:
????????現(xiàn)有B商品在參加秒殺活動,假設(shè)一個購買B商品的線程發(fā)生了死鎖,此時currentValue = 1,這個時候購買B商品的兩個線程同時調(diào)用了lock方法,且value都等于2,同時這兩個線程都進(jìn)入了鎖過期的判斷"if (!StringUtils.isEmpty(currentValue)&& Long.parseLong(currentValue)
以上,就是我們使用redis實現(xiàn)了分布式鎖。
如果你覺得小編寫的對你有用的話就扶貧一下吧,哈哈哈
總結(jié)
以上是生活随笔為你收集整理的redis分布式锁java代码_基于redis实现分布式锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 动态壁纸 例子,andr
- 下一篇: 服装CAD计算机按钮在哪里,富仪服装CA