Thread.join(1000) не ждет завершения работы работника

почему этот код

public static void main(String [] argv){
        Logger l = LoggerFactory.getLogger( "MAIN" );

        Thread thread = new Thread(()->{
            Logger ll = LoggerFactory.getLogger( "WRKR" );
            ll.debug("start t1");
            try {
                Thread.sleep( 10000 );
            } catch (InterruptedException e) {
                throw new RuntimeException( e );
            }
            ll.debug("end t1");

        }) ;
        l.info("main");
        thread.start();
        try {
            Thread.sleep( 8000 );
        } catch (InterruptedException e) {
            throw new RuntimeException( e );
        }

        try {
            l.info("trying to join");
            thread.join(100);
            l.info("joined");
        } catch (InterruptedException e) {
            throw new RuntimeException( e );
        }
        l.info("end main");
    }

производит этот вывод:

10:57:38.871 [main] INFO MAIN - main
10:57:38.879 [Thread-0] DEBUG WRKR - start t1
10:57:46.884 [main] INFO MAIN - trying to join
10:57:46.993 [main] INFO MAIN - joined
10:57:46.993 [main] INFO MAIN - end main
10:57:48.880 [Thread-0] DEBUG WRKR - end t1

Какой смысл join(100) не сообщать, что «рабочий» поток все еще работает? Я ожидал исключения во время выполнения.

«Я ожидал исключения во время выполнения». Почему? В документации указаны только два исключения: «Выдает: IllegalArgumentException — если значение миллис отрицательное InterruptedException — если какой-либо поток прервал текущий поток. Статус прерванного текущего потока очищается, когда выдается это исключение». тайм-аут не указан (метод завершается нормально, никаких исключений не происходит)

user85421 14.06.2024 11:39

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

Mark Rotteveel 14.06.2024 12:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Javadoc для метода join(long millis) гласит: «Ожидает не более миллимиллисекунд, пока этот поток завершится». Он не сообщает о текущем состоянии другого потока, поэтому после вашего звонка thread.join(100); у вас не будет никакой информации о состоянии thread.

Начиная с JDK19, вы можете использовать join с Duration, который возвращает логическое значение, сообщающее, завершился ли поток. Если вы просмотрите исходный код join(Duration), он эквивалентен join(millis); с тестом isTerminated();, поэтому вы можете вызвать thread.isTerminated(), если в данный момент не используете JDK19+.

Приятно знать! В любом случае, к сожалению, я все еще использую Java 17.

DDS 14.06.2024 11:16

В Javadoc для t.join(duration) говорится: «Возврат:...false, если поток не завершился». Это ложь. Возвращаемое значение false не означает, что поток все еще работает. Это означает только то, что время ожидания соединения истекло. Мы можем предположить, что поток работал в какой-то момент до истечения времени ожидания вызова соединения, но у нас нет возможности узнать, как давно это было.

Solomon Slow 14.06.2024 12:35

@SolomonSlow Тогда это не ложь. Конечно, он не может сообщить о состоянии потока после возврата метода...

Mark Rotteveel 14.06.2024 12:37

@MarkRotteveel, документация является явной. В нем говорится, что возвращаемое значение false означает, что поток не завершился. Какой смысл говорить, что возвращаемое значение X означает Y, если Y не гарантированно станет истинным к моменту проверки значения вызывающим объектом? Правдивое описание возвращаемого значения будет означать, что false означает, что время ожидания вызова истекло, и поток в этот момент может все еще работать, а может и не работать.

Solomon Slow 14.06.2024 12:39

@SolomonSlow Да, и это именно то, что он возвращает, если вы посмотрите на код (я посмотрел код Java 21). Возвращаемое значение является результатом Thread.isTerminated(). Другими словами, в момент возврата метода он возвращает состояние завершения. Он не может предсказать будущее, поэтому, если поток завершится на наносекунду позже, он, очевидно, не сможет сообщить об этом.

Mark Rotteveel 14.06.2024 12:43

Если возвращаемое значение не предсказывает будущее, то документация в лучшем случае вводит в заблуждение. И, что вводит в заблуждение, так это то, что это вводит младших разработчиков в заблуждение, заставляя их не думать о том, как состояние некоторого объекта может быть изменено потоком A после того, как поток B запросил его состояние, но до того, как B сможет действовать с информацией. Такое недоразумение, если его не остановить, может привести к архитектурным недостаткам реального коммерческого программного обеспечения.

Solomon Slow 14.06.2024 13:18

@SolomonSlow Он не может предсказать будущее: он знает только, каким было состояние на момент возвращения, и в то время оно было либо прекращено, либо все еще работало. Хотя ваш аргумент, вероятно, иллюстрирует, почему старые методы join не имеют возвращаемого значения (хотя вы, вероятно, тогда возразите, что запрос Thread.isTerminated() также не может предсказать будущее и, следовательно, вводит в заблуждение...).

Mark Rotteveel 14.06.2024 13:39

Другие вопросы по теме