回覆列表
  • 1 # 程式設計師遇見更好的自己

    對於這個問題我們首先想到的是使用synchronized關鍵字,這是一種解決方法,例如:

    public synchronized void setStatus(boolean b) {}

    但synchronized不適合高併發資料,高併發資料會導致程式特別慢,也不適合叢集,負載均衡後資料就會出現問題。

    我們使用另一種解決方法redis分散式鎖,redis為單執行緒服務的,高效的key/value結構,支援高可用的分散式叢集,能夠做到多臺機器上多個程序對同一資料互斥。

    我們講一下redis從建立到使用的過程:

    1、使用maven下載redis依賴的包,在pom.xml中配置:

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>1.5.14.RELEASE</version></dependency>

    2、熟悉redis的指令,redis的中文網址:http://www.redis.cn,我們主要熟悉下setnx指令:設定value值設定成功返回1,當有值時返回0;另一個需要熟悉的指令是getset:先取得以前的值,再設定新值。

    3、新建redis類寫加鎖、解鎖的方法:

    // 自動注入redis

    @Autowired

    private StringRedisTemplate redisTemplate;

    /***

    *加鎖

    * @param key id

    * @param value 當前時間+超時時間

    * @return*/

    public boolean lock(String key, String value) { // 對應命令的setnx

    // 可以設定返回true,不可以設定即有值返回false

    if(redisTemplate.opsForValue().setIfAbsent(key, value)) { return true; }

    // 保證其中只有一個執行緒拿到鎖

    String currentValue = redisTemplate.opsForValue().get(key);

    // 如果鎖過期,儲存進去的鎖小於當前時間

    if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {

    // 獲取上一個鎖的時間

    String oldValue = redisTemplate.opsForValue().getAndSet(key, value);

    if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) { return true; } } return false;}

    /**

    *解鎖

    */public void unlock(String key, String value) {

    try {

    String currentValue = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {

    redisTemplate.opsForValue().getOperations().delete(key); } } catch(Exception e) { log.error(【redis分散式鎖】解鎖異常, {}",e); }

    4、呼叫

    private static final int TIMEOUT = 10 * 1000;// 超時時間10s

    @Autowired

    private RedisLock redisLock;

    // 加鎖

    long time = System.currentTimeMillis() + TIMEOUT;

    String id = "123";

    if (!redisLock.lock(id, String.valueOf(time))){

    throw new XXXException(101, “請求過多請稍後”);}

    // 中間是需要執行的方法

    // 解鎖

    redisLock.unlock(id, String.valueOf(time));

    總結:當前id為空或失效的情況下返回true即可以加鎖;當前id不為空或沒失效的情況下返回false即不能加鎖已有程序在處理。

  • 中秋節和大豐收的關聯?
  • 所有辣椒的名稱及產地?