original link Jakob Jenkov
translator: Palanisamy < Span style= "margin:0px; padding:0px; Word-wrap:break-word "> proofreading: Ding
in Java, deadlocks can be avoided in some cases. This article shows three techniques for avoiding deadlocks:
Lock Order
Deadlocks can easily occur when multiple threads require the same locks, but are locked in different order.
If you can ensure that all threads are getting locks in the same order, the deadlock does not occur. Look at the following example:
thread 1:lock A lock Bthread 2:wait for a lock C (when a locked) thread 3:wait for a wait for B wait fo R C
If a thread (such as thread 3) needs some locks, it must acquire the locks in the order in which they are determined. It can only get the back lock after it has obtained a lock in order from the front.
For example, thread 2 and thread 3 cannot attempt to acquire lock C until lock A is acquired ( translator note: Acquiring lock A is a necessary condition for acquiring lock C ). Because thread 1 already has lock a, threads 2 and 3 need to wait until lock A is released. Then, before they attempt to lock B or C, a lock must be successfully added to a.
Sequential lock-In is an effective mechanism for deadlock prevention. However, this approach requires you to know in advance all the locks that may be used (the translator notes: And to sort the locks appropriately ), but there are times when they are unpredictable.
Lock time limit
Another way to avoid deadlocks is to add a timeout when trying to acquire a lock, which means that the thread will discard the lock request if it exceeds the time limit during the attempt to acquire the lock. If a thread does not successfully acquire all the required locks within a given time frame, it will rollback and release all acquired locks, and then wait for a random time to retry. This random wait time gives other threads a chance to try to acquire the same locks and allow the app to continue running without a lock ().
Here is an example of a scenario where two threads try to get the same two locks in different order, fall back and retry after a timeout has occurred:
Thread 1 Locks athread 2 locks bthread 1 attempts to lock B Yes Blockedthread 2 attempts to lock A Yes Blockedth Read 1 ' s lock attempt on B times Outthread 1 backs up and releases A as Wellthread 1 waits randomly (e.g. 257 Millis) Befo Re retrying. Thread 2 ' s lock attempt on A times Outthread 2 backs up and releases B as Wellthread 2 waits randomly (e.g. Millis) BEF Ore retrying.
In the above example, thread 2 retries and locks up 200 milliseconds earlier than thread 1, so it can successfully acquire two locks first. At this point, thread 1 attempts to acquire lock A and is in a wait state. When thread 2 ends, thread 1 can also obtain the two locks successfully (unless thread 2 or other thread 1 succeeds in acquiring some of the locks before the two locks are successfully obtained).
It is important to note that due to the time-out of the lock, we cannot assume that this scenario must be a deadlock. It may also be because the thread that acquired the lock (which causes other lines to blocks until those) takes a long time to complete its task.
Also, if there are a lot of threads competing for the same resources at the same time, even if there is a timeout and fallback mechanism, it can cause these threads to try repeatedly but never lock. This behavior may not occur if there are only two threads, and the retry time-out is set to between 0 and 500 milliseconds, but if it is 10 or 20 threads, the situation is different. Because these threads have a much higher probability of waiting for equal retry times (or are very close to having problems).
translator Note: The time-out and retry mechanisms are designed to avoid competition at the same time, but when there are many threads, the time-out of two or more threads is the same or the likelihood of approaching is very large, so even after a race to a time-out, they will start retrying at the same time due to the time-out, causing a new round of competition has brought about new problems. )
There is a problem with this mechanism, and in Java it is not possible to set the timeout time for the synchronized synchronization block. You need to create a custom lock or use the tool under the Java.util.concurrent package in Java5. Writing a custom lock class is not complex, but beyond the scope of this article. Subsequent Java Concurrency series will cover the contents of the custom lock.
Deadlock Detection
Deadlock detection is a better mechanism for deadlock prevention, primarily for scenarios where sequential locking and lock timeouts are not possible.
Whenever a thread obtains a lock, it is written down in the data structure (map, graph, and so on) associated with the lock. In addition, whenever a thread requests a lock, it needs to be recorded in this data structure.
When a thread requests a lock failure, the thread can traverse the lock's diagram to see if a deadlock has occurred. For example, thread a requests lock 7, but lock 7 is held by thread B at this time, so thread A can check if thread B has requested a lock currently held by thread A. If thread B does have such a request, then a deadlock occurs (thread A has lock 1, request lock 7, thread B has lock 7, request lock 1).
Of course, deadlocks are generally more complicated than two threads holding each other's locks. Thread A waits for thread B, thread B waits for thread C, thread C waits for thread d, and thread D waits for thread A. Thread A in order to detect deadlocks, it requires a progressive detection of all locks requested by B. Starting with the lock requested by thread B, thread a found thread C and then found thread D, and found that thread D requested the lock to be held by thread A. This is what it knew happened to be a deadlock.
Here is a diagram of the lock occupancy and request between four threads (A,b,c and D). Data structures like this can be used to detect deadlocks.
So what do these threads do when a deadlock is detected?
One possible option is to release all locks, rollback, and wait for a random time to retry. This is similar to a simple lock-out timeout, except that a deadlock has occurred before it can be rolled back, not because the lock request timed out. There are fallback and wait, but if there are a large number of threads competing for the same lock, they will still be repeatedly deadlocked ( Editor's note: The reason is similar to the timeout, Cannot fundamentally mitigate the competition ).
A better solution is to prioritize these threads so that one (or several) of the threads fall back and the rest of the threads continue to hold the locks they need, just as they do without a deadlock. If the priority given to these threads is fixed, the same batch of threads will always have a higher priority. To avoid this problem, you can set a random priority when a deadlock occurs.
Extended reading: Translator's note
- The third edition of Modern operating system §6.2~§6.7
Java Learning to avoid deadlocks