Redisによるロックメカニズムの実装

8234 ワード

最近ロックに関する文章を読んで、自分の理解をメモします.
0 x 0の原理
ロックは、マルチスレッドが同じリソースを同時に変更またはアクセスすることを解決するために設計されています.ロックの種類には多くの種類があり、私が現在知っているロックでは、楽観的なロックを除いて、他のロックの原理は大きく異なります.つまり、各スレッドがアクセスできる場所にタグを設定して、リソースのアクセス権を記録します.たとえば、あるリソースTargetが存在し、A、B、Cの3つのスレッドがTargetの値を変更し、変数を設定することができます.
boolean isAccessible = true;

AスレッドがTargetにアクセスする場合は、isAccessibleがtrueであるかどうかを確認し、trueである場合はアクセス権を取得し、isAccessibleをfalseに設定します.このとき、BスレッドもTargetにアクセスすると、isAccessibleがfalseであることが判明し、アクセス権限が取得されない場合、Bスレッドは、変数がtrueであるまでisAccessibleをwhileループで判断してアクセス権を取得することができる.スレッドへのアクセスが完了したら、isAccessibleタグをtrueに設定します.注意すべきは、以上のプロセスが正しく実行されることを保証するには、2つの条件を満たさなければならない:第1、isAccessibleは各スレッドが表示されることを保証しなければならない.第2に、タグとしての変数の判断と修正は原子操作である必要がある.まず、volatileキーワードを使用してマルチスレッドの可視性を保証することができ、次に、java内のアトミックBooleanオブジェクトおよびそのcompareAndSetメソッドなどの原子オブジェクトを使用して原子操作を保証することができる.しかし、上記の例では、ロックの実現は単一プロセスの下にある.環境がマルチプロセスまたは分散型の場合、ロックの実装をどのようにシミュレートしますか?サードパーティキャッシュを使用して、各プロセスがアクセスできるタグを格納できます.redisおよびそのsetnxメソッドは、ロックとしての2つの大きな条件を満たしています.redisは、各スレッドがアクセスできることを保証します.setnx(key,value)メソッドは、このkeyが存在する場合、0を返します.keyが存在しない場合は、key-valueキー値ペアを挿入し、1を返します.
0 x 1例
まず小さなdemoを書きます.
redisロックツールクラス
package com.fly.lock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisLock {

    //   redis 
    private static JedisPoolConfig config;
    private static JedisPool pool;
    static {
        config = new JedisPoolConfig();
        config.setMaxTotal(30);
        config.setMaxIdle(10);
        pool = new JedisPool(config, "192.168.233.200", 6379);
    }

    /**
     *  target  
     * @param target
     */
    public static void lock(Object target) {
        //  jedis
        Jedis jedis = pool.getResource();
        //result  setnx    ,    0
        Long result= 0L;
        while (result < 1) {
            //  target redis     ,   0;  , redis   target   ,   1
            result = jedis.setnx(target.getClass().getName() + target.hashCode(), Thread.currentThread().getName());
        }

        jedis.close();
    }

    /**
     *  target  
     * @param target
     */
    public static void unLock(Object target) {

        Jedis jedis = pool.getResource();
        //  redis target      
        Long del = jedis.del(target.getClass().getName() + target.hashCode());
        jedis.close();
    }

    /**
     *    target  ,       true,       false
     * @param target
     * @return
     */
    public static boolean tryLock(Object target) {

        Jedis jedis = pool.getResource();
        Long row = jedis.setnx(target.getClass().getName() + target.hashCode(), "true");
        jedis.close();
        if (row > 0) {
            return true;
        }
        return false;
    }
}

テストクラス
package com.fly.test;

import com.fly.lock.RedisLock;

class Task {

    public void doTask() {
        //  
        RedisLock.lock(this);

        System.out.println("    : " + Thread.currentThread().getName());
        System.out.println("    : " + this.hashCode());

        try {
            System.out.println("doing...");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("  : " + this.hashCode());

        //  
        RedisLock.unLock(this);
    }

}

public class Demo {

    public static void main(String[] args) {
        Task task = new Task();

        Thread[] threads = new Thread[5];
        for (Thread thread : threads) {
            thread = new Thread(()->{
                task.doTask();
            });
            thread.start();
        }

    }

}

出力結果:
----------------------------------------------
    : Thread-0
    : 2081499965
doing...
  : 2081499965
----------------------------------------------
    : Thread-2
    : 2081499965
doing...
  : 2081499965
----------------------------------------------
    : Thread-1
    : 2081499965
doing...
  : 2081499965
----------------------------------------------
    : Thread-4
    : 2081499965
doing...
  : 2081499965
----------------------------------------------
    : Thread-3
    : 2081499965
doing...
  : 2081499965

redisロックを削除した後、結果を実行します.
----------------------------------------------
----------------------------------------------
    : Thread-2
    : 1926683415
----------------------------------------------
    : Thread-1
doing...
    : Thread-0
----------------------------------------------
    : Thread-3
    : 1926683415
doing...
    : 1926683415
doing...
----------------------------------------------
    : 1926683415
doing...
    : Thread-4
    : 1926683415
doing...
  : 1926683415
  : 1926683415
  : 1926683415
  : 1926683415
  : 1926683415

Process finished with exit code 0

redisという性質を利用して、分布式ロックを実現することができて、もちろん設計はきっと複雑です!redis公式はredlockを提供しているようで、研究する時間があります.