Mode of communication
To achieve synergy among multiple threads, such as the order in which threads execute, getting the results of a thread's execution, and so on.There are four categories of interoperability between threads:
- File sharing
- Network Sharing
- Shared variable
- Thread Coordination API provided by JDK
- suspend/resume,wait/notify,park/unpark
File sharing
public class MainTest { public static void main(String[] args) { // Thread 1 - Write data new Thread(() -> { try { while (true) { Files.write(Paths.get("test.log"), content = "current time" + String.valueOf(System.currentTimeMillis())); Thread.sleep(1000L); } } catch (Exception e) { e.printStackTrace(); } }).start(); // Thread 2 - Read Data new Thread(() -> { try { while (true) { Thread.sleep(1000L); byte[] allBytes = Files.readAllBytes(Paths.get("test.log")); System.out.println(new String(allBytes)); } } catch (Exception e) { e.printStackTrace(); } }).start(); } }
Variable Sharing
public class MainTest { // Shared variable public static String content = "empty"; public static void main(String[] args) { // Thread 1 - Write data new Thread(() -> { try { while (true) { content = "current time" + String.valueOf(System.currentTimeMillis()); Thread.sleep(1000L); } } catch (Exception e) { e.printStackTrace(); } }).start(); // Thread 2 - Read Data new Thread(() -> { try { while (true) { Thread.sleep(1000L); System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } }).start(); } }
Network Sharing
Thread Collaboration - JDK API
The JDK provides API support for scenarios where multithreaded collaboration is required to complete a task.
A typical scenario for multithreaded collaboration is the producer-consumer model.(Thread blocking, thread wakeup)
Example: Thread 1 buys buns, and if there are no buns, it does not execute.Thread 2 produces the bun and notifies thread-1 to continue execution.
API - Deprecated suspend and resume
Role: Call suspend to suspend the target thread, resume to resume thread execution.
/** Bakery */ public static Object baozidian = null; /** Normal suspend/resume */ public void suspendResumeTest() throws Exception { // Start Thread Thread consumerThread = new Thread(() -> { if (baozidian == null) { // If there is no bun, go into waiting System.out.println("1,Enter Wait"); Thread.currentThread().suspend(); } System.out.println("2,Buy buns and go home"); }); consumerThread.start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); consumerThread.resume(); System.out.println("3,Notify consumers"); }
The main reason for being discarded is that it is easy to write code that does not deadlock.So replace it with wait/notify and park/unpark mechanisms
Examples of suspend and resume deadlocks
1. Use in synchronization code
/** Deadlock suspend/resume.Susnd does not release locks like wait, so it is easy to write deadlock codes */ public void suspendResumeDeadLockTest() throws Exception { // Start Thread Thread consumerThread = new Thread(() -> { if (baozidian == null) { // If there is no bun, go into waiting System.out.println("1,Enter Wait"); // The current thread gets the lock and hangs synchronized (this) { Thread.currentThread().suspend(); } } System.out.println("2,Buy buns and go home"); }); consumerThread.start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); // Restore consumerThread after acquiring the lock synchronized (this) { consumerThread.resume(); } System.out.println("3,Notify consumers"); }
2. suspend after resume
/** suspend/resume causing program to hang permanently */ public void suspendResumeDeadLockTest2() throws Exception { // Start Thread Thread consumerThread = new Thread(() -> { if (baozidian == null) { System.out.println("1,No buns, enter waiting"); try { // Add a little delay to this thread Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } // The hang here executes after resume Thread.currentThread().suspend(); } System.out.println("2,Buy buns and go home"); }); consumerThread.start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); consumerThread.resume(); System.out.println("3,Notify consumers"); consumerThread.join(); }
W ait/notify mechanism
These methods can only be called by the owner thread of the same object lock, that is, written in the synchronization block, or an IllegalMonitorStateException exception will be thrown.
The wait method causes the current thread to wait, join the object's wait collection, and discard the currently held object lock.
The notify/notifyAll method wakes up one or all threads waiting for this object lock.
Note: Although wait is automatically unlocked, there is a requirement for order, if the call to wait method is not started until notify is called, the thread will always be in WAITING state.
wait/notify code sample
/** Normal wait/notify */ public void waitNotifyTest() throws Exception { // Start Thread new Thread(() -> { synchronized (this) { while (baozidian == null) { // If there is no bun, go into waiting try { System.out.println("1,Enter Wait"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("2,Buy buns and go home"); }).start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); synchronized (this) { this.notifyAll(); System.out.println("3,Notify consumers"); } }
Examples of deadlocks
/** wait/notify that causes the program to wait permanently */ public void waitNotifyDeadLockTest() throws Exception { // Start Thread new Thread(() -> { if (baozidian == null) { // If there is no bun, go into waiting try { Thread.sleep(5000L); } catch (InterruptedException e1) { e1.printStackTrace(); } synchronized (this) { try { System.out.println("1,Enter Wait"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("2,Buy buns and go home"); }).start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); synchronized (this) { this.notifyAll(); System.out.println("3,Notify consumers"); } }
park/unpark mechanism
Threads invoke parks while waiting for a License, and the unpark method provides a License for the specified thread
The calling order of the park and unpark methods is not required.
After many calls to unpark, call park, and the thread runs directly.
However, it does not overlap, that is, if the park method is called several times in a row, the first time it gets a "license" to run directly, and subsequent calls go into waiting.
/** Normal park/unpark */ public void parkUnparkTest() throws Exception { // Start Thread Thread consumerThread = new Thread(() -> { while (baozidian == null) { // If there is no bun, go into waiting System.out.println("1,Enter Wait"); LockSupport.park(); } System.out.println("2,Buy buns and go home"); }); consumerThread.start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); LockSupport.unpark(consumerThread); System.out.println("3,Notify consumers"); }
Examples of deadlocks
/** Deadlocked park/unpark */ public void parkUnparkDeadLockTest() throws Exception { // Start Thread Thread consumerThread = new Thread(() -> { if (baozidian == null) { // If there is no bun, go into waiting System.out.println("1,Enter Wait"); // The current thread gets the lock and hangs synchronized (this) { LockSupport.park(); } } System.out.println("2,Buy buns and go home"); }); consumerThread.start(); // After 3 seconds, produce a bun Thread.sleep(3000L); baozidian = new Object(); // Restore consumerThread after acquiring the lock synchronized (this) { LockSupport.unpark(consumerThread); } System.out.println("3,Notify consumers"); }
spurious wakeup
Warning! Previous code used if statement to determine whether to enter the wait state, is wrong!
The official recommendation is that wait conditions should be checked in a loop because threads in a wait state may receive error alerts and false wakeups, and if they are not checked in a loop, the program will exit without meeting the end conditions.
Pseudo wake-up refers to a thread that is not awakened by api calls such as notify, notifyall, unpark, etc. It is caused by a more underlying cause.