A deadlock is one in which two or more threads block a lock that waits for another thread in a deadlock state to hold. Simply put, the threads are not getting the lock they need to talk to each other.
Deadlocks usually occur when multiple threads are simultaneously requesting the same set of locks in a different order.
For example, if thread 1 locks A, then tries to lock the B, and thread 2 already has a lock on B, and then tries to lock a, then the deadlock occurs. Thread 1 never get B, thread 2 will never get a, they'll always block it down. This is a dead lock.
public class TreeNode {
TreeNode parent = null;
List children = new ArrayList ();
Public synchronized void AddChild (TreeNode child) {
if (!this.children.contains (child)) {
This.children.add ( Child);
Child.setparentonly (this);
}
Public synchronized void Addchildonly (TreeNode child) {
if (!this.children.contains)
{ This.children.add (child);
}
Public synchronized void SetParent (TreeNode parent) {
this.parent = parent;
Parent.addchildonly (this);
}
Public synchronized void Setparentonly (TreeNode parent) {
this.parent = parent;
}
}
If thread 1 calls the Parent.addchild (child) method while another thread 2 calls the Child.setparent () method, the parent in two threads represents the same object, and so does the child, and a deadlock occurs.
Thread 1:parent.addchild (child); Locks Parent
--> child.setparentonly (parent);
Thread 2:child.setparent (parent); Locks Child
-->parent.addchildonly ();
First, thread 1 invokes Parent.addchild (child). Because Addchild () is synchronized, thread 1 locks the parent object and other threads are inaccessible.
Then thread 2 calls Child.setparent (parent). Because SetParent () is synchronized, thread 2 locks the child object and other threads cannot access it.
Now the child and the parent are locked by two different threads. Thread 1 then attempts to invoke the Child.setparentonly () method, but because the child object is now locked by thread 2, the call is blocked. Thread 2 also attempts to invoke Parent.addchildonly (), but because the parent object is now locked by thread 1, thread 2 is blocked at the method. The result is that two threads are blocked and waiting to acquire the lock held by the other, which is the deadlock. I'll never get it.
There's another kind of deadlock,
Thread 1 Locks A, wait for B
Thread 2 locks B, wait for C
Thread 3 Locks C, wait for D
Thread 4 locks D, wait for A
How to avoid deadlocks
1. Lock order: From the above already know, cause the deadlock is the reason is the thread between each other need to lock the resources, then, when more than one thread needs the same number of locks, if the order of the lock is different, it is easy to happen deadlock. The solution is to ensure that all threads acquire locks in the same order.
2. Lock time: When attempting to acquire a lock, a timeout is added, which means that the thread discards the request for the lock if it exceeds that time during the attempt to acquire the lock. If a thread does not successfully acquire the required lock within a given time, the rollback is rolled back and all the acquired locks are released, and then wait for some time to try again. (After the lock timeout you can do something else, and then go back and repeat the logic before the lock.) )
There is a problem with this mechanism, and the mechanism for timeouts and retries is to avoid competition at the same time, however, when there are many threads, the likelihood of two or more threads having the same or near timeout is very high, so even if the timeout is due to the competition, new competition will occur, Bring a new problem. Also, it is not possible to set the timeout time for synchronized synchronization blocks in Java. You need to create a custom lock.
3. Deadlock Detection:
Deadlock detection is a better deadlock prevention mechanism, primarily for scenarios where sequential locking and lock timeouts are not possible.
Whenever a thread obtains a lock, it is written down in the thread-and-lock-related data structure (map, graph, and so on). In addition, whenever a thread requests a lock, it needs to be recorded in this data structure.
When a thread requests a lock failure, this thread can traverse the diagram of the lock to see if a deadlock occurs. For example, thread a requests lock 7, but lock 7 is held by thread B at this time, and thread A can check to see if thread B has requested the lock that thread A is currently holding. If thread B does have such a request, there is a deadlock (thread A has a lock of 1, a request for a lock of 7; thread B has a lock of 7, and a request for a lock of 1).
Of course, deadlocks are generally more complex 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 to detect deadlocks, it needs to progressively detect all locks requested by B. Starting with the lock requested by thread B, thread a found thread C, then found thread D, and found that thread D requested a lock that was held by thread a itself. That's what it's like to know that a deadlock has occurred.
So what do these threads do when a deadlock is detected?
A feasible approach is to release all locks, rollback, and wait a random time before retrying. This is similar to a simple lock timeout, but the difference is that only the deadlock has occurred before it is rolled back, not because the lock request timed out. Although there are fallback and waiting, if a large number of threads compete with the same locks, they will still be deadlocked repeatedly (editor's note: The reason is similar to timeout and cannot fundamentally mitigate competition).
A better solution would be to prioritize these threads and let one (or several) of the threads roll back, leaving the remaining threads to keep the locks they need without a deadlock. If the priority given to these threads is fixed, the same thread will always have a higher priority. To avoid this problem, you can set a random priority when a deadlock occurs.