Distributed Keys Two Redis implementation

A recent auction of a project will use distributed lock, found on the Internet a result, there are three ways to achieve. 1. Database locking mechanism, 2.redis lock, 3.zookeeper. Taking into account the use mysql to achieve this one would be affected in terms of performance, zookeeper is not very good at. So use redis to achieve.

The first: the use of watch command to achieve redis


After the age session1 monitoring the use of watch command before the modification, and then updated in session2 age, session1 executing exec, when the command of age should be checked whether the value of change, and now is already happening: As shown above change, so the return on failure.

I wrote some java code based on the icon

Copy the code
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;


public class RedisWatchTest extends  Thread {

    private String auctionCode;
    public RedisWatchTest
(String auctionCode) {
        super(auctionCode);
        this.auctionCode = auctionCode;
    }
    private static int bidPrice = 100;

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "主线程运行开始!");
        //更改key为a的值
        Jedis jedis=new Jedis("127.0.0.1",6379);
        jedis.set("goodsprice","0");
        System.out.println("输出初始化值:"+jedis.get("goodsprice"));
        jedis.close();
        RedisWatchTest thread1 = new RedisWatchTest("A001");
        RedisWatchTest thread2  = new RedisWatchTest("B001");
        thread1.start();
        thread2.start();
        try{
            thread1.join();
            thread2.join();
       }catch(InterruptedException e){
           e.printStackTrace();
       }
        System.out.println(Thread.currentThread().getName() + "主线程运行结束!");
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程运行开始 ");
        Jedis jedis=new Jedis("127.0.0.1",6379);
        try {
            IF (Thread.currentThread () getName () == "B001.") { 
                SLEEP (1000); 
            } 
        } the catch (InterruptedException E) { 
            e.printStackTrace (); 
        } 
        // monitoring KEY 
        jedis.watch ( "goodsprice") ; 
        // A advanced 
        String jedis.get V = ( "goodsprice"); 
        Integer = Integer.valueOf IV (V); 
        // conditions gave too 
        IF (bidPrice> IV) { 
            the Transaction jedis.multi TX = (); / / open transaction 
            Integer BP = iv + 100; 
            // bid is successful, uncommitted transactions 
            tx.set ( "goodsprice", String.valueOf (BP)); 
            System.out.println ( "child thread" + auctionCode + "set success ");
jedis.close(); System.out.println (. Thread.currentThread () getName () + "end of the thread run"); } }
Copy the code

The results:
main main thread running start!
Output initial value: 0
B001 thread running start 
A001 thread running start 
sub-thread A001set successful
child thread B001set successful
child threads B001, bid: 100, bid time: 76,269,463,819,581
B001 thread running end
child thread A001, failed bid
A001 threads run ended
ended main main thread running!

The code is in the main thread which opened two sub-thread, let B001 1s time to wait, let A001 to watch the highest price, and then let him wait 2s time before the A001 affairs exec. This time B001 has been successful bid, the final bid should be returned A001 failure.

The second: use of setnx redis command realized

on setnx Detailed reference of this article is the following, he took the proper implementation of the two locking and unlocking.
https://www.cnblogs.com/linjiqin/p/8003838.html
below are the codes implemented by setnx

Copy the code
import redis.clients.jedis.Jedis;

import java.util.Collections;

/**
 * @author chen
 * @date 2018/4/30 16:09
 */
    public class RedisSetNXTest extends  Thread{

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    private String auctionCode;
    public RedisSetNXTest
            (String auctionCode) {
        super(auctionCode);
        this.auctionCode = auctionCode;
    }
    private static int bidPrice = 100;

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "主线程运行开始!");
        //更改key为a的值
        Jedis jedis=new Jedis("127.0.0.1",6379);
        jedis.set("goodsprice","0");
        System.out.println("输出初始化值:"+jedis.get("goodsprice"));
        jedis.close();
        RedisSetNXTest thread1 = new RedisSetNXTest("A001");
        RedisSetNXTest thread2  = new RedisSetNXTest("B001");
        thread1.start();
        thread2.start();
        try{
            thread1.join();
            thread2.join();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "主线程运行结束!");
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程运行开始 ");
        Jedis jedis=new Jedis("127.0.0.1",6379);
        try {
            if(Thread.currentThread().getName()=="B001"){
                sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //让A先拿到锁
        boolean isOk=  tryGetDistributedLock(jedis, "goods_lock", Thread.currentThread().getName() , 10000);

        try {
            if(Thread.currentThread().getName()=="A001"){
                sleep(2000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(isOk) {
            System.out.println("子线程"+this.auctionCode + "get locked");
            V = jedis.get String ( "goodsprice"); 
            Integer = iv Integer.valueOf (v); 
            // conditions gave too 
            IF (bidPrice> iv) { 

                Integer BP = iv + 100; 
                // bid is successful, uncommitted transactions 
                jedis.set ( "goodsprice", String.valueOf (BP)); 
                System.out.println ( "child thread" + this.auctionCode + ", the bid:" + jedis.get ( "goodsprice" ) + ", the time bid : " 
+ to System.nanoTime ()); } the else { System.out.println ("! bid price lower than the current "); } Boolean isOk1 = releaseDistributedLock (jedis," goods_lock ", Thread.currentThread () getName (). ); IF (isOk1) { the System.out.println ( "child thread" + this.auctionCode + "lock release"); } } {the else System.out.println ( "child thread" + auctionCode + "does not get locked"); } jedis.close (); . System.out.println (Thread.currentThread () getName () + "end of the thread is running "); } / ** * try to obtain a distributed lock * @param jedis Redis client * @param lockKey lock * @param requestId request identification * @param expireTime extended time * @return whether for success * / public boolean tryGetDistributedLock (Jedis jedis, String lockKey, String requestId, int expireTime) { Result = jedis.set String (lockKey, the requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); IF (LOCK_SUCCESS.equals (Result)) { return to true; } return to false; } private static final Long RELEASE_SUCCESS = 1L; /** * 释放分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1])
else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections
.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } }
Copy the code

The results:
main main thread running start!
Output initial value: 0
A001 thread running start 
B001 thread running start 
sub-thread B001 did not get the lock
B001 thread running end
child thread lock to get the A001
sub-thread A001 bid: 100, bid time: 77,389,730,033,100
child thread releases the lock A001
A001 threads run ended
ended main main thread running!

the same code in the main thread which opened two sub-thread, let wait B001, A001 let go to get a lock. Then let the B001 in the case did not get the lock down operations redis, the code is not to judge the site to get the lock, A001 after execution because to get a lock, so you can bid.

This is achieved in two ways should belong to the optimistic locking bar the implementation may not meet any temporary spike like concurrent environment. In short specific analysis of specific issues still have it.

Guess you like

Origin www.cnblogs.com/zhuyeshen/p/10979396.html