Метод Thread.join () в Java

Метод Thread.join () в Java

 

1. обзор

В этом руководстве мы обсудим различные методыjoin() в классеThread. Мы подробно рассмотрим эти методы и некоторые примеры кода.

Подобноwait() иnotify() methods,join() - еще один механизм межпоточной синхронизации.

Вы можете быстро взглянуть наthis tutorial, чтобы узнать больше оwait() иnotify().

2. МетодThread.join()

Метод соединения определен в классеThread:

public final void join () выбрасывает InterruptedException Ожидание этой нити, чтобы умереть.

Когда мы вызываем методjoin() в потоке, вызывающий поток переходит в состояние ожидания. Он остается в состоянии ожидания, пока указанный поток не завершится.

Мы можем видеть это поведение в следующем коде:

class SampleThread extends Thread {
    public int processingCount = 0;

    SampleThread(int processingCount) {
        this.processingCount = processingCount;
        LOGGER.info("Thread Created");
    }

    @Override
    public void run() {
        LOGGER.info("Thread " + this.getName() + " started");
        while (processingCount > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOGGER.info("Thread " + this.getName() + " interrupted");
            }
            processingCount--;
        }
        LOGGER.info("Thread " + this.getName() + " exiting");
    }
}

@Test
public void givenStartedThread_whenJoinCalled_waitsTillCompletion()
  throws InterruptedException {
    Thread t2 = new SampleThread(1);
    t2.start();
    LOGGER.info("Invoking join");
    t2.join();
    LOGGER.info("Returned from join");
    assertFalse(t2.isAlive());
}

При выполнении кода следует ожидать результатов, похожих на следующие:

INFO: Thread Created
INFO: Invoking join
INFO: Thread Thread-1 started
INFO: Thread Thread-1 exiting
INFO: Returned from join

The join() method may also return if the referenced thread was interrupted. В этом случае метод выдаетInterruptedException.

Наконец,if the referenced thread was already terminated or hasn’t been started, the call to join() method returns immediately.

Thread t1 = new SampleThread(0);
t1.join();  //returns immediately

3. Thread.join() Методы с тайм-аутом

Методjoin() будет продолжать ждать, если указанный поток заблокирован или обработка занимает слишком много времени. Это может стать проблемой, поскольку вызывающая нить перестает отвечать на запросы. Чтобы справиться с этими ситуациями, мы используем перегруженные версии методаjoin(), которые позволяют нам указать период ожидания.

Есть дваtimed versions, которые перегружают методjoin():

“public final void join(long millis_) выдает InterruptedException_Waits at most миллис milliseconds for this thread to die. A timeout of 0 means to wait forever.”

“public final void join(long millis, int nanos_) выбрасывает InterruptedException_Waits at most millis milliseconds plus nanos_ наносекунды, чтобы этот поток умер ». _

Мы можем использовать рассчитанные по времениjoin(), как показано ниже:

@Test
public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout()
  throws InterruptedException {
    Thread t3 = new SampleThread(10);
    t3.start();
    t3.join(1000);
    assertTrue(t3.isAlive());
}

В этом случае вызывающий поток ожидает примерно 1 секунду для завершения потока t3. Если поток t3 не завершается в этот период времени, методjoin() возвращает управление вызывающему методу.

Timedjoin() зависит от ОС для синхронизации. Таким образом, мы не можем предположить, чтоjoin() будет ждать точно столько, сколько указано.

4. Thread.join() Методы и синхронизация

Помимо ожидания завершения, вызов методаjoin() имеет эффект синхронизации. join() creates a happens-before relationship:

«Все действия в потоке происходят до того, как какой-либо другой поток успешно вернется из соединения () в этом потоке».

Это означает, что когда поток t1 вызывает t2.join (), то все изменения, сделанные t2, видны в t1 по возвращении. Однако, если мы не вызываемjoin() или не используем другие механизмы синхронизации, у нас нет никакой гарантии, что изменения в другом потоке будут видны текущему потоку, даже если другой поток завершился.

Следовательно, даже несмотря на то, что вызов методаjoin() для потока в завершенном состоянии возвращается немедленно, нам все равно нужно вызывать его в некоторых ситуациях.

Мы можем увидеть пример неправильно синхронизированного кода ниже:

SampleThread t4 = new SampleThread(10);
t4.start();
// not guaranteed to stop even if t4 finishes.
do {

} while (t4.processingCount > 0);

Чтобы правильно синхронизировать приведенный выше код, мы можем добавить timedt4.join() внутри цикла или использовать какой-либо другой механизм синхронизации.

5. Заключение

Методjoin() весьма полезен для межпоточной синхронизации. В этой статье мы обсудили методыjoin() и их поведение. Мы также рассмотрели код с использованием методаjoin().

Как всегда, полный исходный код можно найтиover on GitHub.