По идее метода join(), если я правильно его понимаю, он должен передавать управление программой тому потоку, на объекте которого был вызван, в то время как тот поток который этот вызов произвел, должен ждать.
Однако, если мы имеем несколько объектов потока, для которых идут вызовы метода join() подряд, то второй тоже запускается.
То есть, методе main мы имеем такой код:
try {
thread01.join();
thread02.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
То по логике, сразу после выполнения вызова thread01.join();, метод main должен был остановиться и ждать пока thread01 не вернет ему управление программой, но логирование показывает, что вместо этого, он выполняет еще и thread02.join(); и только этого переходит в режим ожидания.
Почему так?
Это что означает, что метод join(), срабатывает только в тех случаях, когда после него не идет еще один join(), или тут блок try, имеет какой-то особый смысл? Помогите пожалуйста разобраться.
Полный код потоков:
public class CounterOfSpace {
private int counterOfSpaces;
private int counterOfWords;
private String text;
private Thread thread01;
private Thread thread02;
public CounterOfSpace(String text) {
this.text = text;
}
void startAll() {
System.out.println("Start program");
calcWords();
calcSpaces();
thread01.start();
thread02.start();
try {
thread01.join();
thread02.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finish program");
}
private void calcSpaces() {
thread01 = new Thread(new Runnable() {
@Override
public void run() {
if (text.length() == 0) return;
for (char c : text.toCharArray()) {
if (c == ' ') {
counterOfSpaces++;
System.out.println("counterOfSpaces "+counterOfSpaces);
}
}
}
});
}
private void calcWords() {
thread02 = new Thread(new Runnable() {
@Override
public void run() {
if (text.length() == 0) return;
String[] words = text.split(" ");
for (String word : words) {
if (!word.equals(" ")) {
counterOfWords++;
System.out.println("counterOfWords "+counterOfWords);
}
}
}
});
}
}
По идее метода join(), если я правильно его понимаю, он должен передавать управление программой тому потоку,
Это не совсем корректно, поток должен уходить в спящее состояние, а вот кому отдать управление решает шедулер.
Однако, если мы имеем несколько объектов потока, для которых идут вызовы метода join() подряд, то второй тоже запускается.
Что никак не противоречит парадигме. В данном случае мы имеем три истории с двумя точками синхронизации:
Main Thread1 Thread2
<init> <init> <init>
running running? finished? running? finished?
join t1 finished running? finished?
join t2 finished finished
Данный код гарантирует, что после завершения t1.join поток t1 будет завершен, но не гарантирует, что он не завершится до вызова t1.join, что очевидно и происходит в этом случае. К моменту вызова t1.join поток t1 может быть в любом состоянии, даже если ему приходится считать тяжелые данные продолжительное время - формально это разрешено, хоть на практике такое будет встречаться нечасто. Вкупе с
логирование показывает
это говорит о том, что, скорее всего, поток просто очень быстро заканчивает работу, а вы принимаете это за несоответствующий спецификации феномен. В таких проблемах не стоит полагаться на логирование, потому что его синхронизационные отношения по отношению к основной программе туманны, и для меня не было бы неожиданным несоблюдение порядка строчек в выводе или длительные (относительно происходящих в программе процессов) задержки при выводе. Также стоит умеренно полагаться на временные замеры подобных вещей, потому что стандартный источник времени может быть не монотонным и возвращать меньшие значения на последующие вызовы, в результате чего будет выглядеть, будто программа выполняется в обратном порядке.
При желании можно заглянуть в исходный код Thread и увидеть, что join реализован через wait и защищен isAlive-гардами от случайных пробуждений, поэтому метод join вернет не раньше, чем поток перестанет возвращать true на isAlive.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости