SpringBoot use distributed lock

Often encounter concurrency security issues in the project, then we can use locks to thread synchronization. So we can be modified using the methods or code blocks synchronized keyword depending on the situation. You can also use java 5 after Lock to achieve, compared with the synchronized keyword, Lock's more flexible, can lock timeout, fairness and other advantages. But the synchronized keyword and scope Lock current application only if distributed deployment, it can not guarantee that only one thread of a data access at the same time, then we can consider the use of an intermediate layer

Next, a brief introduction of a distributed lock himself open source usage

A. Import dependencies

<dependency>
    <groupId>cn.gjing</groupId>
    <artifactId>tools-redis</artifactId>
    <version>1.0.0</version>
</dependency>

II. Start classes marked notes

/**
 * @author Gjing
 */
@SpringBootApplication
@EnableRedisLock
public class TestRedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestRedisApplication.class, args);
    }
}

III. Specific use

Parameter information

  • key: corresponding to the lock key
  • value: random string
  • expire: lock expiration time, in seconds
  • timeout: acquiring the lock timeout, in milliseconds
  • retry: reacquire lock interval, in milliseconds

1. annotation mode

  • @Lock(String key, int expire , int timeout, int retry)
/**
 * @author Gjing
 **/
@RestController
public class TestController {
    private static int num = 20;
    @GetMapping("/test1")
    @Lock(key = "test1")
    public void test1() {
        System.out.println("当前线程:" + Thread.currentThread().getName());
        if (num == 0) {
            System.out.println("卖完了");
            return;
        }
        num--;
        System.out.println("还剩余:" + num);
    }
}

Results of pressure measurement ab
ab1

2. Manual control mode

  • Injection AbstractLock dependence
    @Resource
    private AbstractLock abstractLock;
  • To lock in place to join abstractLock.lock (), to acquire the lock to unlock a successful return value, otherwise return null

String lock(String key, String value, int expire, int timeout, int retry)

  • Place to be released using abstractLock.release (), the current release of the lock is unlocked successfully returned the key, otherwise return null

String release(String key, String value)

  • Use Cases
/**
 * @author Gjing
 **/
@RestController
public class LockController {

    @Resource
    private AbstractLock abstractLock;

    private static int num = 10;

    @GetMapping("/test2")
    public void test2() {
        String lock = null;
        try {
            lock = this.abstractLock.lock("testLock", RandomUtil.generateMixString(5), 20, 10000, 50);
            System.out.println("当前线程:" + Thread.currentThread().getName());
            if (num == 0) {
                System.out.println("卖完了");
                return;
            }
            num--;
            System.out.println("还剩余:" + num);
        } finally {
            this.abstractLock.release("testLock", lock);
        }
    }
}

ab pressure measurement results
ab2

note! ! !

The only best lock corresponding key, otherwise it will create multiple methods while sharing a lock, causing bad results, the incoming unlock value, it must be a lock to get the acquisition value, otherwise it will fail to unlock, unlock the other to avoid people lock

3. Rewrite Exception Handling

After a request to acquire the lock timeout, timeout exception information return by default, if you want to customize the return can be inherited AbstractLockTimeoutHandler timeout exception handling classes

/**
 * @author Gjing
 **/
@Component
public class LockExceptionHandler extends AbstractLockTimeoutHandler {

    @Override
    public ResponseEntity timeoutAfter(TimeoutException e) {
        // TODO: 实现自定义处理的逻辑  
    }
}

4. custom implementation locking

This project uses Redis and lua scripts that implement lock combination, such as if you want to use your own lock, can be inherited AbstartetLock class

/**
 * @author Gjing
 **/
public class DemoLock extends AbstractLock {
    @Override
    public String lock(String s, String s1, int i, int i1, int i2) {
        return null;
    }

    @Override
    public String release(String s, String s1) {
        return null;
    }
}

IV. Use recommended

The lock recommends using a separate stand-alone redis, if it is in redis sentinel cluster situation is different in redis sentinel cluster, we have more than one redis, has a master-slave relationship between them, such as from a main two. We set the corresponding command to write data to the main library, then sync to the library. When we apply for a lock when the correspondence is a command  setnx mykey myvalue , in redis sentinel cluster, this command first fell to the main library. Then suppose the main library down, but this data is not enough time to synchronize from the library, sentinel from a library of election-based library. At this time, our new main library is not mykey this data, at this time if another client execution  setnx mykey hisvalue , will be successful, that can be locked. This means that, at this time there are two client received a lock


The use of any problems and BUG, ​​Comments welcome, and I will respond promptly update

Guess you like

Origin yq.aliyun.com/articles/706641