Layout: Post title: “Java multithreaded wait/notify mechanism” subtitle: “1. Wait causes the current executing thread to wait. 2. 2018-10-07 08:00:00 author: “Header-img” : “img/ post-BG-2015.jpg “Catalog: True tags: – Multi Thread

Application scenarios

Controls the execution order of multiple threads

Multiple thread applications, thread execution order is not sequential, random.

If you want to execute threads in the specified order, why would you want to execute threads in the specified order? If two threads access shared data, one thread depends on the results of the other thread’s execution, so one must follow the other. How to achieve one after the other? See below.


code

Thread 1 thread 2 main thread {thread 1.start(); Thread 1. The join (); // Make sure thread 1 and thread 2 execute thread 2.start(); }Copy the code

How do you make sure of that? 1. The thread 1. The start (); Thread 1 executes.

2. Thread one. The join (); Causes the main thread to wait.

3. Thread 1 completes execution // When the thread completes execution, the JVM automatically calls the thread exit() thread exit(). // Wake up notifyAll all other threads

//Thread.exit()

/**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
        if(group ! = null) { group.threadTerminated(this); group = null; } /* Aggressively null out all reference fields: see bug 4006245 */ target = null; /* Speed the release of some of these resources */ threadLocals = null; inheritableThreadLocals = null; inheritedAccessControlContext = null; blocker = null; uncaughtExceptionHandler = null; } /** * Notifies the group that the thread {@code t} has terminated. * * <p> Destroy the groupif all of the following conditions are
     * true: this is a daemon thread group; there are no more alive
     * or unstarted threads in the group; there are no subgroups in* this thread group. * * @param t * the Thread that has terminated */ void threadTerminated(Thread t) { synchronized (this) {// Get the built-in lock on the current object.if(nthreads == 0) { notifyAll(); // Wake up all threads}if(daemon && (nthreads == 0) && (nUnstartedThreads == 0) && (ngroups == 0)) { destroy(); }}}Copy the code

4. Thread 2. The start (); Thread 2 executes.

Start the program and keep it running

Some systems are more complex, such as third-party payment systems, which have many microservices. Some are Web programs and some are Java programs. How do Java programs run? 1. Use while(true) 2. Use wait to cause the main thread to wait.


code

// Load all spring configuration files: At the same time, start a lot of Spring threads... // Multithreading: The Spring container provides many bean services that can be invoked locally or externallywhile(true){ MainTest.class.wait(); // cause the main thread to wait, so that the program is always running}}Copy the code

Wait /notify and blocking

One thread waits until another thread wakes it up. Otherwise, it keeps blocking.

Object.wait differs from Thread.join

Join (), which causes the current thread to wait. Join () refers to the current thread, not the thread object of join()

Object.wait

Thread.join

Encapsulates wait().

//Thread

/**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          ifany thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when Throw this exception is thrown. */ public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0); // cause the current thread (the main thread) to wait, instead of the thread object calling JOIN () to wait}}else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay); now = System.currentTimeMillis() - base; }}}Copy the code

Notify and notifyAll

1. Notify // Wakes up one thread at random 2. NotifyAll // Wakes up all other threads

The relationship between wait/notify and the built-in lock of an object

In either wait or Notify, you must first acquire an object’s built-in lock. The official document (https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait).


17.2. Wait Sets and Notification Every object, in addition to having an associated monitor, has an associated wait set. A wait set is a set of threads.

When an object is first created, its wait set is empty. Elementary actions that add threads to and remove threads from wait sets are atomic. Wait sets are manipulated solely through the methods Object.wait, Object.notify, and Object.notifyAll.

Wait set manipulations can also be affected by the interruption status of a thread, and by the Thread class’s methods dealing with interruption. Additionally, the Thread class’s methods for sleeping and joining other threads have properties derived from those of wait and notification actions.

Docs.oracle.com/javase/spec…

code

//Thread.join()

/**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          ifany thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when */ public final synchronized void join(long millis) Obtain the built-in lock of the current object. Throws InterruptedException {Long Base = System.CurrentTimemillis (); long now = 0;if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0); }}else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay); now = System.currentTimeMillis() - base; }}}Copy the code

Why do we have to acquire the built-in lock of an object and wait/notify later? Otherwise, an error is reported – the current thread does not own the built-in lock on the object.


Why is the JVM designed this way? What’s the reason? Ensure synchronous access to data for the same object.


Refer to www.jianshu.com/p/f4454164c…

reference

Juejin. Cn/post / 684490…