Happy Moment
Today, another one of my best buddies got off and I'm left alone
I'm spilling my guts to a girl I like.
Me: I'll never find a girlfriend in my life
Her: How can that be, you are very good, there will be many girls who would like to be your girlfriend
I inwardly snickered and asked, So will you be my girlfriend?
Her: I am enlightening you, don't be gracious!

Online issues
Sudden alarms in the production environment, alarm messages:
attempt to unlock lock, not locked by current thread by node id: b9df1975-5595-42eb-beae-bdc5d67bce49 thread-id: 52
Check the log to find the corresponding stack information
Exception in thread "thread0" : attempt to unlock lock, not locked by current thread by node id: b9df1975-5595-42eb-beae-bdc5d67bce49 thread-id: 52
at $unlockAsync$4(:616)
at $onComplete$0(:187)
at .notifyListener0(:578)
at (:552)
at (:491)
at (:184)
at (:181)
at (:607)
at (:492)
at (:41)
at (:748)
Translated.
Attempt to release the lock from the current thread (node id: b9df1975-5595-42eb-beae-bdc5d67bce49 thread-id: 52)
That is: the current thread is attempting to release a lock on another thread.
How can I release someone else's lock?

Basic Review
Before we troubleshoot the problem, let's figure out
node id: b9df1975-5595-42eb-beae-bdc5d67bce49 thread-id: 52
node id
cap (a poem)thread-id
what?
with respect tothread-id
I'm sure we all understand that it's the id of the thread that threw the exception, right? That'snode id
And?
I'll guide you with the eight-letter words.
Ask:
redisson
usableredis
What data type is used to implement the lock in theAnswer:
hash
Q: That
hash
hit the nail on the headkey
、field
、value
What are the respective values ofAnswer:
key
The value of is the lock name.field
The value ofThread id
,value
The value of is the number of reentriesQ: If multiple services go to acquire a lock at the same time, the
field
It is not possible that the values of the locks are the same, e.g., the thread in which Service A acquires the lock has thethread-id
is 52, and the thread in which Service B acquires the lock'sthread-id
Also 52At this point you are not a little panicked, but still tough answer: it is possible that the same
Q: So there's no problem, the thread for service A (
thread-id=52
) gets the lock and is performing business processing, the thread of service B (thread-id=52
) can also get a lock, it's not a lock of loneliness?A: Uh... Uh...
Obviously a detail was missed, and that isfield
Its value is notThread id
Rathernode id:thread-id
, for example:b9df1975-5595-42eb-beae-bdc5d67bce49:52
And thisnode id
just likeredisson
(used form a nominal expression)Instance id
The following is an example of how to differentiate between the distributedredisson
an actual example
Redisson Distributed Locking Implementation Source Code → Why Redisson Client is Recommended There's a very detailed description that's worth checking out for you guys
Releasing someone else's lock
talk is sheap show me the code

The code, I'm sure everyone can understand it, but I'll explain it anyway
- constructor's lock
- Attempt to acquire lock, wait time 1s, hold lock 3s
- If the lock is acquired, the business is processed; if it is not acquired, it is printed.
Lock acquisition failed
finally
Guarantees that locks are released in both exception and non-exception cases
Isn't that normal, but it really doesn'tbug
(question tag)

Let's adjust the code.

(of a computer) runmultiThreadLock
The anomaly is coming.

From the printout, we should be able to analyze what the problem is
- Thread 52 acquires the lock and executes in the business
- Thread 53 tries to acquire the lock, but the lock is held by thread 52
- Thread 53 Failed to acquire lock in 1s
- Thread 53, come in.
finally
If the lock is held, release the lock.redisson
When releasing a lock, an exception is thrown if the thread holding the lock is not the current thread.
Thread 53, what's wrong with you, how can you release someone else's lock? You can't blame thread 53, we wrote the code, look at the commit logs, we have to pull this two arm out!!!!

Forget it. Let's not pull it out. Let's get on with fixing it.
Problem fixing
Now that you've found the problem, fixing it is simple in several ways
Increase in waiting time
Increase the wait time for acquiring the lock, but this way can only reduce the exception, not completely fix the exception; because there will be multiple threads competing for the lock at the same time, it is not appropriate to set the wait time to any amount, unless it is set to no timeout, but setting it to no timeout may result in too many waiting threads, causing insufficient threads to use the situation. This is not recommended.
automatic release
get rid offinally
This is equivalent to eliminating the source of the exception, so there will be no exceptions.
If you can't solve the problem, solve the person who raised it.
Do not actively release the lock, let the lock automatically due to release, because we set the lock holding time is 3s, 3s after the automatic expiration of the release. However, in actual business, we often set the lock holding time is relatively large (much larger than the average length of business execution), to ensure that the business will not be executed concurrently, if the business execution is completed without releasing the lock, it will lead to a long time the lock is invalidly occupied, and the subsequent thread to obtain the lock can only be waiting in vain. This method is not recommended
Record acquisition status
Look directly at the code and you'll understand

What happens if the business takes longer than 3s to execute? Let's change the sleep time to 5s and execute the followingtestLock
, you will find the same anomaly again!!!!

Let's analyze, the lock holding time is 3s, while the business execution time is 5s, that is to say, the lock has expired before the business has finished executing.redis
It's automatically released, and when we release the lock after the business execution, the lock is gone, so how can we release it? Soredisson
throws an exception; so when releasing the lock, you also need to add a condition
if (acquired && ())
acquired
indicates whether the current thread has acquired the lock, while the()
Indicates whether there are threads holding locks, if both aretrue
If you have a lock, then it is the current thread that holds the lock, and releasing it is no problem. It can be used, but it's not recommended because there are more elegant ways to handle it
judgemental holder
That's a much more elegant way of writing it.

It is straightforward to determine whether the lock is held by the current thread and release it if it is; you don't have to worry about whether the lock is held by another thread or whether it will be released automatically when it expires. Recommended method
summarize
- Sample code address:redisson-spring-boot-demo
- The purpose of locking is to ensure that the business of single-threaded execution, so the lock must be set to hold the length of time a little larger, otherwise the extreme case, the business is still in the execution of the lock but the expiration of the lock, contrary to the original purpose of locking!
- Locks must be actively released, must be actively released, must be actively released, not business related
- When releasing a lock, determine whether it is held by the current thread, it is not your lock, why do you release it?