проблема с использованием методов isAlive (), Interrupt () и stop () потока внутри ExecuterService - PullRequest
0 голосов
/ 18 июня 2020

Я обнаружил, что метод isAlive () не работает при выполнении потока с использованием ExecuterService. И методы interrupt () и stop () также не работают.
Код, который я использовал:

Thread t1=new Thread(()->{
    try{
        Thread.sleep(10000);
    } catch(InterruptedExeception ie){
        System.out.println("Interrupted");
    }
    Thread.sleep(5000);
    System.out.println("It's Done");
});
ExecuterService excuter=Executers.newSingleThreadExecuter();
excuter.execute(t1);
Thread.sleep(2000);
System.out.println(t1.isAlive());
Thread.sleep(2000);
t1.interrupt();
t1.stop();

Мой ожидаемый результат:

true
Прервано

Фактический результат:

false
Готово

Мне нужна причина для такого поведения. И я хочу знать, каково решение проблемы и как я использую эти методы, когда поток работает внутри ThreadPool.

Ответы [ 2 ]

2 голосов
/ 18 июня 2020
  1. Метод stop() не работает. Вы не можете остановить подобные потоки. Поток должен разрешить свою остановку; вы, например, обновите логическое значение (volatile или AtomicBoolean-style), и поток будет запускать al oop, и на каждом l oop проверяет это логическое значение; если это ложь, это заканчивается. Невозможно остановить произвольные потоки на своем пути. Вообще. Вы можете найти в Google информацию о том, почему Thread.stop устарел (и фактически больше не работает, хотя метод все еще существует, в первую очередь как средство для документации о том, почему вы больше не можете этого делать).

  2. Потоки реализуют runnable, поэтому вам даже разрешено передавать этот поток методу-исполнителю, но вся инфраструктура потока вообще не используется. Вы должны обновить этот код до Runnable r = () -> {...} и передать его. Ваш код в том виде, в каком он написан, вводит вас в заблуждение, заставляя думать, что это запущенный поток. Это не так, поэтому вы получаете false вместо .isAlive().

  3. Исполнители, как правило, не раскрывают способ, которым они выполняют работу, они просто делают это. Если вы хотите проверить, выполняется ли задание, установите для логического (volatile или AtomicBoolean) логического значения true при входе и false при выходе. В качестве альтернативы, не беспокойтесь о службе исполнителя, просто запустите свой поток, если вы действительно хотите использовать функции потока, такие как .isAlive().

1 голос
/ 18 июня 2020

t1 не является потоком.

t1 - это экземпляр Thread, но экземпляр Thread - это не то же самое, что поток, и то, как вы используете t1, поток никогда не создается. Думайте об экземпляре Thread как о дескрипторе , который вы используете для создания потока и управления им. Поток будет создан, если ваша программа вызвала t1.start(), а затем все вызовы t1.isAlive() и t1.interrupt() и t1.stop() будут работать с этим новым потоком.

Помимо экземпляра Thread, t1 также оказывается экземпляром Runnable, что и требуется для вызова executer.execute(...). Наличие Runnable просто означает, что t1 имеет метод run(). Существует несколько способов вызова метода run():

  • Вы можете запустить поток, t1.start(), и в этом случае новый поток вызовет его:
  • Вы могли (вы сделали ) передать его Executor. Когда вы это делаете, Executor принимает меры к тому, чтобы один из своих рабочих потоков вызывал ваш run() метод.
  • Вы можете просто назвать его - t1.run() - что ничем не отличается от вызова любого другого метода, определяемого вашим кодом.
  • Вы можете передать его любому другому библиотечному методу, которому требуется Runnable. (Я не знаю, сколько их, может быть, много.)

Если вы хотите, чтобы t1.run() вызывался в потоке, который может контролировать ваш код, тогда вызовите t1.start() чтобы создать этот поток. Если вы хотите, чтобы он вызывал службу-исполнитель, потоки которой вы не должны пытаться контролировать, тогда сделайте то, что вы сделали: вызовите excuter.execute(t1);

Просто не делайте и то, и другое. Вероятно, это не то, что вам нужно.


PS. Если вы хотите продолжить использование службы Executor, вам, вероятно, следует изменить свое объявление t1. Поскольку в этом случае это должно быть только Runnable, вы можете написать:

Thread t1=new Runnable(()->{
    ...
});

Таким образом, люди, читающие ваш код, не будут чесать в затылке и удивляться, знаете ли вы, что делаете.

...