Distributed Lock: to achieve single-node redis

First, the concurrency between threads

If we want to execute two threads synchronize, you only need to add sychronzied or use Reetrantlock class to ensure the implementation of multiple threads within the same jvm synchronization process.

So if this system is distributed, for example: Thread on both servers concurrently executing want to how to do it?

And we want to achieve is that this sub-sub-drop:

In fact, the most important is for the operation of the lock, obtain and release locks.

Two, redis achieve

1, the lock

set(key,线程的id,30,NX)

The lock is achieved by placing the data into a redis, this set methods: If the current is not redis this key, returns 1 if 0 is returned. This way you can. set way to control concurrency between different threads, only the implementation of this method returns 1 when considered acquire the lock.

The latter two parameters are set expiration time. If you do not set what happens? For example, thread A acquires the lock, then the program fails died, the lock has been not been released, the other threads the server will not get the lock. So, set an expiration time of significance: After reaching the expiration date, then the data is automatically canceled (of course, you want to set a good memory redis elimination mechanism), which is the release of the lock, does not affect the other thread can obtain the lock set .

Some say it :( Can it be achieved are the following pseudo-code)

setnx(key,1)
expire(key,30)

Redis use these two commands to achieve: the answer is NO

We must ensure that the process is a locked atomic operations , for example, client thread A's end after executing setnx after (key, 1) is dead, the lock is still not acquired by another thread.

2, the lock is released

A thread is executed after completion of synchronization code blocks, performs lock is released

del(key)

This method is it okay? NO, NO, NO. Absolutely not

Consider this: If the expiration date is currently set for 30 seconds, then after the execution thread A get locked in the content synchronization code block, after 30 seconds, redis saw the time, put the key removed, the lock is released, and this time it did not execute a finished yet, so the thread Bset a bit and found that you can get the lock, thread B in a pleasant play, but this time it thread a executed over (redis not notice it releases the lock ), this man thought he was still lock it, then release it, this time, the lock thread B has also been removed, the key is this man does not know the lock is removed. In this way there is a problem of concurrency. Like being cuckolded I do not know the same.

We can set stored value set to the thread id (personal thoughts are: + id uniquely identifies the server thread = value)

加锁:
String threadId = Thread.currentThread().getId()
set(key,threadId ,30,NX)

解锁:
if(threadId .equals(redisClient.get(key))){
del(key)
}

But it appeared a problem, lock release is not an atomic operation. I rely on there will be problems ah.

Let's look at a scenario like this:

Or the case of the previous example, after the judge finished thread A is not the current thread id, then the key moment expired. B thread got locked, and then performs A still appeared in the above case.

We should replace del, use lua script to achieve, the buckle 1.

String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] 
then return redis.call('del', KEYS[1]) else return 0 end";

redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId));

A small partners have to say, then thread A expires first, still running, thread B are executed to acquire the lock, which does not conform to the rules ah. Here we have to solve this problem.

We can set up a thread knife guards, like JR guard LeBron James (something a few years ago). To a Imperial guards, in java, is the guardian of the thread! Of course, you have to know what is the guardian of the thread.

This daemon thread is only one role,

When the 29 seconds have passed, the thread A has not been performed, this time daemon thread will execute expire instructions for the lock "continued life" for 20 seconds. Daemon thread begins execution from 29 seconds to execute once every 20 seconds.

 

When thread A executed, this daemon thread will be over.

Published 134 original articles · won praise 91 · views 160 000 +

Guess you like

Origin blog.csdn.net/weixin_44588495/article/details/104563365