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

1. Общ преглед

В този урок ще обсъдим различните методи join () в класа Thread . Ще влезем в подробностите за тези методи и някои примерни кодове.

Подобно на методите wait () и notify () , join () е друг механизъм за синхронизация между нишките.

Можете да разгледате набързо този урок, за да прочетете повече за wait () и уведомяване () .

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

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

публично окончателно 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

Методът join () може също да се върне, ако препратената нишка е била прекъсната . В този случай методът изхвърля InterruptException .

И накрая, ако посочената нишка вече е прекратена или не е стартирана, методът за повикване към join () се връща незабавно .

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

3. Методи Thread.join () с изчакване

Методът join () ще продължи да чака, ако посочената нишка е блокирана или обработката отнема твърде много време. Това може да се превърне в проблем, тъй като извикващата нишка няма да реагира. За да се справим с тези ситуации, използваме претоварени версии на метода join () , които ни позволяват да посочим период на изчакване.

Има две времеви версии, които претоварват метода join () :

„Публичното окончателно пусто присъединяване (дълги мили ) изхвърля InterruptedException

Уейтс най-много в милисекунди милисекунди за тази тема, за да умре. Времето за изчакване от 0 означава да чакате вечно. "

„Публично окончателно невалидно присъединяване ( long milis, intnanos ) изхвърля InterruptedException

Уейтс най-много в милисекунди милисекунди плюс Нанос наносекунди за тази тема, за да умре. "

Можем да използваме времето за присъединяване (), както по-долу:

@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 () връща контрола към извикващия метод.

Времевото присъединяване () зависи от операционната система за синхронизиране. Така че, не можем да предположим, че join () ще изчака точно толкова, колкото е посочено.

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

В допълнение към изчакването до прекратяване, извикването на метода join () има ефект на синхронизация. join () създава връзка преди случване:

„Всички действия в дадена нишка се случват преди всяка друга нишка да се върне успешно от join () на тази нишка.“

Това означава, че когато нишка 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);

За да синхронизираме правилно горния код, можем да добавим t4.join () в цикъла или да използваме друг механизъм за синхронизация.

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

Методът join () е доста полезен за синхронизация между нишките. В тази статия обсъдихме методите join () и тяхното поведение. Също така прегледахме кода, използвайки метода join () .

Както винаги, пълният изходен код може да бъде намерен в GitHub.