Fourth article on concurrent programming
A large house has two functions: sleeping, learning and being irrelevant.
Now Xiao Nan has to learn and the little girl has to sleep, but if she only uses one room (one object lock), the concurrency is very low.
Prepare multiple rooms (multiple object locks) for solution
deadlock
When a thread needs to acquire multiple locks at the same time, deadlocks can easily occur.
The t1 thread acquires the A object lock, and then wants to acquire the B object lock
The t2 thread acquires the B object lock, and then wants to acquire the A object lock
Locate Deadlock
- To detect deadlocks, you can use the jconsole tool or use jps to locate the process id and jstack to locate the deadlock:
Let's start with an example of thread hunger, using sequential locking to solve previous deadlocks
Sequential Locking Solution
It has the following characteristics relative to synchronized
- Interruptable
- Timeout can be set
- Can be set to fair lock
- Supports multiple conditional variables
Like synch, reentrant is supported
Reentrant
Reentrant refers to the use of a thread that, if it acquires the lock for the first time, has the right to acquire it again because it is the owner of the lock
If the lock is not reentrant, the second time the lock is acquired, the lock itself will be blocked
Basic Grammar
Fixed run order
For example, you must print 2 and 1 first
wait notify version
Thread 1 outputs a5 times, thread 2 outputs b5 times, and thread 3 outputs c5 times.Now I want to output how abcabcabcabcabc is implemented
package com.example.demo; import lombok.extern.slf4j.Slf4j; @Slf4j public class Test27 { public static void main(String[] args) { WaitNotify waitNotify = new WaitNotify(1, 5); new Thread(() -> { waitNotify.print("a", 1, 2); }).start(); new Thread(() -> { waitNotify.print("b", 2, 3); }).start(); new Thread(() -> { waitNotify.print("c", 3, 1); }).start(); } } /** * Output waiting for tag next tag * a 1 2 * b 2 3 * c 3 1 */ class WaitNotify { /** * Print * @param str * @param waitFlag * @param nextFLag */ public void print(String str, int waitFlag, int nextFLag) { for (int i = 0; i < loopNumber; i++) { synchronized (this) { while (flag != waitFlag) { try { this.wait(); } catch (Exception e) { e.printStackTrace(); } } System.out.println(str); flag = nextFLag; this.notifyAll(); } } } /** * Wait tag */ private int flag; /** * Number of loops */ private int loopNumber; public WaitNotify(int flag, int loopNumber) { this.flag = flag; this.loopNumber = loopNumber; } } package com.example.demo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test2 { public static void main(String[] args) throws InterruptedException { AwaitSignal awaitSignal = new AwaitSignal(5); Condition a = awaitSignal.newCondition(); Condition b = awaitSignal.newCondition(); Condition c = awaitSignal.newCondition(); new Thread(() -> { awaitSignal.print("a", a, b); }).start(); new Thread(() -> { awaitSignal.print("b", b, c); }).start(); new Thread(() -> { awaitSignal.print("c", c, a); }).start(); Thread.sleep(1000); awaitSignal.lock(); try { System.out.println("Start..."); a.signal(); } finally { awaitSignal.unlock(); } } } class AwaitSignal extends ReentrantLock { private int loopNumber; public AwaitSignal(int loopNumber) { this.loopNumber = loopNumber; } /** * Parameter 1 prints, parameter 2 enters that lounge, parameter 3 next Lounge * @param str * @param current * @param next */ public void print(String str, Condition current, Condition next) { for (int i = 0; i < loopNumber; i++) { lock(); try { current.await(); System.out.println(str); next.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { unlock(); } } } }