redis分布式锁java代码_基于redis实现分布式锁
“?在上一篇文章中介紹了動態配置定時任務,其中的原理跟spring 定時任務注解@Scheduled一樣的,都是通過線程池和定義執行時間來控制。來思考一個問題,如果我們的定時任務在分布式微服務里面呢?在分布式微服務里面一個微服務肯定可以有多個實例的,在上一篇文章當中配置的定時任務就會有可能存在多個,顯然定時任務被多次執行并不是我們想要的結果,這個時候我們的分布式鎖機制就出現了!”
(分布式鎖有很多實現方式,以前我們都是使用synchronized來處理并發請求,雖然也支持分布式,但是總有一些業務不適合,比如秒殺系統的多個商品同時開啟秒殺,同一時刻只能完成一件商品的減庫存操作,這樣就造成了系統的性能瓶頸,也不符合秒殺系統的設計思想。由于 synchronized 無法做到細粒度的控制,從而引進了分布式鎖,分布式鎖能夠完成 synchronized 無法做到的點。下面我們要介紹的是基于redis的實現方式)。
01
—
引入redis依賴
引入springboot官方的redis依賴。
引入一個hutool工具包的依賴,功能很全的一個java工具包,強烈推薦使用。
<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實現
怎么使用redis實現呢,先來看下redis的兩個命令。
setnx:如果key不存在就跟set一樣的作用,如果key存在則什么都不做
getandset:返回上一次的value,并設置新的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 當前時間+超時時間 * @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 當前時間+超時時間 */ 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()); } }}在上一篇文章當中的代碼中使用
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 任務ID * @param service 業務類 * @param keyword 關鍵字參數 */ 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
—
秒殺系統下的應用
這里我們來解釋一下為何在lock方法當中加上 “//如果鎖過期” 后面的代碼,我們以商品秒殺系統舉例比較好理解。
假如我們不加上這段代碼,在加鎖之后的業務流程拋出了一個異常,且這個異常我們沒有捕獲并處理,那么我們接下來的解鎖操作是不會執行的,這個時候我們的鎖就變成了死鎖,我們就可以使用getandset命令來進行解鎖,舉個?:
????????現有B商品在參加秒殺活動,假設一個購買B商品的線程發生了死鎖,此時currentValue = 1,這個時候購買B商品的兩個線程同時調用了lock方法,且value都等于2,同時這兩個線程都進入了鎖過期的判斷"if (!StringUtils.isEmpty(currentValue)&& Long.parseLong(currentValue)
以上,就是我們使用redis實現了分布式鎖。
如果你覺得小編寫的對你有用的話就扶貧一下吧,哈哈哈
總結
以上是生活随笔為你收集整理的redis分布式锁java代码_基于redis实现分布式锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 动态壁纸 例子,andr
- 下一篇: 服装CAD计算机按钮在哪里,富仪服装CA