If there is no use of distributed locks, the scene is like this:
This is an ordinary update user age function, the layers of code are as follows, access controller layer, an update, a query :
This is the service layer. We use the controdlatch gun to simulate the simultaneous concurrency of the thread. The firing gun is set to 32, that is, 32 threads request to modify the age at the same time.
Use the thread pool to submit the multi-threaded task. Look at the code to know that we have the operation to judge the age here. When the query user query is greater than 0, we will update the user age-1 method. Wait to see if there is any
here is sql. See two sql, one query user age, one will perform user age minus 1 each time,
here is user data, we can see that user UID is UR12324 user, his age is 30, then we To adjust 32 threads to operate to reduce his age
We request this method:
can see that the age in the library has been reduced to -2, in the case of no lock, the query is not What role, if you add a synchronized or lock lock, you can certainly avoid this situation. However, this article is discussed in a multi-instance or distributed environment. This locking method still causes problems. If you are interested, you can try it out.
We will start implementing a redis distributed lock to avoid this. The situation occurs, first talk about the implementation of the idea:
1, the thread calls the lock method before the request is accessed, and the lock is used to generate a random number and save it in the thread local variable and a key of redis, this key Set the validity period to 200ms, the specific value is adjusted according to the business execution time, and the locking is successful;
2. Other threads try to access and take out its local variables and compare them with a key in redis. If they are inconsistent, it means there is a lock. This thread sleeps for a while, try to lock again;
3. The successful locking thread deletes the lock it holds after the operation ends (implemented with lua, guarantee atomicity, compare and delete the lock in it) In the process, other threads will not lock successfully, let other threads lock again to perform the task;
Description: The lock time is 200ms to prevent the deadlock after the thread hangs, and will automatically release after
@@ @Look at the lock code we wrote:
片1: Use redislock to implement lock to rewrite it Method
段2: Try to lock the method:
段3: Unlock the method, first get its random number from the thread local variable, then call the lua script, compared with the key in redis, If it is the same, delete it, otherwise it returns 0;
This is the lua script method. This method can guarantee the atomicity of judgment and deletion. In this process, no thread can operate this key:
We basically write the lock, to test whether there is no use:
We add the lock and unlock method before and after this method, the use of the same way as the lock lock, we re-age the age to 30 and then test it
Here you can see the situation of each thread competing for the lock, then look at the execution result
Here we can see that although 32 threads execute concurrently, this value does not Becomes a negative number, the lock is successful.
We can see that the last 2 threads did not execute the method
At this point, the lock is successful, you can test it more in a distributed environment, in extreme cases. What should be done after the failure of unlocking can also be decided by ourselves, more flexible than redission, most of the redis with lock Good is a single instance, there may be problems in the cluster, there is a chance we can use zk to achieve.