Принцип реализации метода соединения в классе Thread

Java

1. Введение

join() — это метод класса Thread.Согласно определению документа jdk, функция метода join() состоит в том, чтобы дождаться окончания потока, то есть текущий поток ожидает выполнения другого поток, который вызывает метод join() для завершения перед его выполнением. Обычно он используется в основном основном потоке для ожидания завершения выполнения других потоков, вызывающих метод join(), прежде чем продолжить выполнение основного основного потока.

    /**
     * Waits for this thread to die.
     *
     */
    public final void join() throws InterruptedException

2. Пример использования

На следующих двух примерах давайте посмотрим, что делает использование метода join().

1. Случай, когда метод join() не используется

public class CreateThreadTest {
    public static void main(String[] args) {
        System.out.println("主线程执行开始");
        Thread threadA = new Thread(new RunnableTest(), "线程A");
        threadA.start();
        System.out.println("主线程执行结束");
    }
}

class RunnableTest implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "执行开始");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "执行结束");
    }
}

Результат выполнения следующий:

主线程执行开始
线程A执行开始
主线程执行结束
线程A执行结束

Поскольку время выполнения вышеупомянутого подпотока относительно велико, выполнение подпотока не заканчивается до тех пор, пока не завершится выполнение основного потока.

2. Когда используется метод join()

public class CreateThreadTest {
    public static void main(String[] args) {
        System.out.println("主线程执行开始");
        Thread threadA = new Thread(new RunnableTest(), "线程A");
        threadA.start();
        try {
            threadA.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程执行结束");
    }
}

class RunnableTest implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "执行开始");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "执行结束");
    }
}

Результат выполнения следующий:

主线程执行开始
线程A执行开始
线程A执行结束
主线程执行结束

После вызова метода join() в дочернем потоке threadA мы обнаруживаем, что основной поток будет ждать завершения выполнения дочернего потока, прежде чем продолжить выполнение.

3. Принцип реализации метода join()

Давайте более подробно рассмотрим метод join() в исходном коде класса Thread (JDK1.8):

    public final void join() throws InterruptedException {
        join(0);
    }

    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);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

В приведенном выше коде есть два кода, на которые следует обратить внимание: один:

public final synchronized void join(long millis) throws InterruptedException {}

Метод-член добавляет синхронизированный и описание синхронизированное (это).Кто это? это сам объект дочернего потока threadA. Другими словами, основной поток удерживает блокировку threadA, объекта дочернего потока.

Второй:

while (isAlive()) {
    wait(0); 
}

Обратите внимание, что этот метод ожидания () является методом класса Object, то есть основной строкой после выполнения метода ожидания (). Процесс снимет блокировку объекта threadA и войдет в состояние ожидания до тех пор, пока он снова не будет разбужен. Все знают, что с ожиданием() должно быть уведомление().Когда будет уведомление? В исходном коде JVM:

//一个c++函数:
void JavaThread::exit(bool destroy_vm, ExitType exit_type) ;
//里面有一个贼不起眼的一行代码
ensure_join(this);

static void ensure_join(JavaThread* thread) {
  Handle threadObj(thread, thread->threadObj());

  ObjectLocker lock(threadObj, thread);

  thread->clear_pending_exception();

  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);

  java_lang_Thread::set_thread(threadObj(), NULL);

  //同志们看到了没,别的不用看,就看这一句
  //thread就是当前线程,是啥?就是刚才例子中说的threadA线程
  lock.notify_all(thread);

  thread->clear_pending_exception();
}

Когда выполнение дочернего потока threadA завершится, jvm автоматически разбудит поток, заблокированный на объекте threadA, который в нашем случае является основным потоком. В этот момент объект потока threadA был уведомлен обо всех, так что основной поток может продолжать работу.

4. Резюме

Вызовите метод threadA.join() в основном главном потоке, поскольку метод join() является синхронизированным методом, поэтомуОсновной поток сначала будет удерживать блокировку объекта потока.. Затем вызовите метод wait() в методе join(),Основной поток снимет блокировку объекта потока потока и войдет в состояние ожидания.. Наконец, выполнение потока threadA заканчивается, JVM вызоветlock.notify_all(thread);Разбудите поток, удерживающий блокировку объекта threadA, то есть основного потока, поэтомуОсновной поток будет продолжать выполняться.


Ссылаться на:

[Java] Принцип работы метода join() в классе Thread

Как метод соединения класса Thread в Java реализует ожидание?