Java Multithread-Thread Communication

Keywords: Java JDK network

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.

Posted by shab620 on Tue, 03 Sep 2019 12:14:44 -0700