Redis:多線程修改同一個Key使用watch+事務(mutil)實現樂觀鎖

來源:互聯網
上載者:User

標籤:排列   and   thread   str   測試   dex   nts   resource   jedis   

本篇文章是通過watch(監控)+mutil(事務)實現應用於在分布式高並發處理等相關情境。下邊先通過redis-cli.exe來測試多個線程修改時,遇到問題及解決問題。

高並發下修改同一個key遇到的問題:

1)定義一個hash類型的key,key為:lock_test,元素locker的值初始化為0。

2)實現高並發下對locker元素的值遞增:定義64個多線程,並發的對lock_test元素locker的值進行修改。

package com.dx.es;import java.util.concurrent.CountDownLatch;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;public class Test_UnLock {    public static void main(String[] args) {        final JedisPool pool = RedisUtil.getPool();        // 獲得jedis對象        Jedis jedis = pool.getResource();        jedis.hset("lock_test", "locker", "0");        String val = jedis.hget("lock_test", "locker");        System.out.println("lock_test.locker的初始值為:" + val);        jedis.close();        int threahSize = 64;        final CountDownLatch threadsCountDownLatch = new CountDownLatch(threahSize);        Runnable handler = new Runnable() {            public void run() {                Jedis jedis = pool.getResource();                Integer integer = Integer.valueOf(jedis.hget("lock_test", "locker"));                jedis.hset("lock_test", "locker", String.valueOf(integer + 1));                jedis.close();                threadsCountDownLatch.countDown();            }        };        for (int i = 0; i < threahSize; i++) {            new Thread(handler).start();        }        // 等待所有並行子線程任務完成。        try {            threadsCountDownLatch.await();        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("complete");        val = jedis.hget("lock_test", "locker");        System.out.println(val);    }}

此時,會出現以下問題:

  1. A線程擷取key的值為0,而B線程也擷取jkey的值0,則A把key值遞增為1,B線程也實現把key值遞增為1。兩個線程都執行了key值修改:0到1。
  2. 在1)中最終key修改為了1,但是c線程擷取key的值為0(因為c線程讀取key值時,a、b線程還未觸發修改,因此c線程讀取到的值為0),此時d線程讀取到的值為1(因為d線程讀取key值時,a、b線程已觸發修改,一次d線程取到的值為1)。
  3. 此時假設d線程優先觸發遞增,則在c線程未觸發提交之前d線程已經把值修改了2,但是c此時並不知道在它擷取到值到修改之前這段時間發生了什麼,直接把值修改1。

此時執行列印結果為:

lock_test.locker的初始值為:0complete24 #備忘:也可能是其他值,可能是正確值64的可能性比較小。
通過watch(監控)+mutil(事務)解決上邊的問題:redis-cli.exe下的事務操作:
# 事務被成功執行redis 127.0.0.1:6379> MULTIOKredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> INCR user_idQUEUEDredis 127.0.0.1:6379> PINGQUEUEDredis 127.0.0.1:6379> EXEC1) (integer) 12) (integer) 23) (integer) 34) PONG
並發情況下使用watch+mutil操作:

事務塊內所有命令的傳回值,按命令執行的先後順序排列。 當操作被打斷時,返回空值 nil 。

A線程:

# 監視 key ,且事務成功執行redis 127.0.0.1:6379> WATCH lock lock_timesOKredis 127.0.0.1:6379> MULTIOKredis 127.0.0.1:6379> SET lock "huangz"QUEUEDredis 127.0.0.1:6379> INCR lock_timesQUEUEDredis 127.0.0.1:6379> EXEC1) OK2) (integer) 1

B線程:

# 監視 key ,且事務被打斷redis 127.0.0.1:6379> WATCH lock lock_timesOKredis 127.0.0.1:6379> MULTIOKredis 127.0.0.1:6379> SET lock "joe"        # 就在這時,另一個用戶端修改了 lock_times 的值QUEUEDredis 127.0.0.1:6379> INCR lock_timesQUEUEDredis 127.0.0.1:6379> EXEC                  # 因為 lock_times 被修改, joe 的事務執行失敗(nil)

上邊示範了A、B線程並發下的watch+mutil操作情況。

需要掌握Redis 事務命令:

Watch 命令用於監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。可用版本:>= 2.2.0

       
       
       
       
       
       
序號 命令及描述
1 DISCARD
取消事務,放棄執行事務塊內的所有命令。
2 EXEC
執行所有事務塊內的命令。
3 MULTI
標記一個事務塊的開始。
4 UNWATCH
取消 WATCH 命令對所有 key 的監視。
5 WATCH key [key ...]
監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。

 

Redis:多線程修改同一個Key使用watch+事務(mutil)實現樂觀鎖

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.