Прервать спящую нить - PullRequest
       7

Прервать спящую нить

5 голосов
/ 22 августа 2011

Попытка прервать работающий поток, в данном примере t1, который выполняется потоком в пуле потоков.

t2 - это тот, который отправляет прерывание.

I 'Я не могу остановить работу t1, t1 не получает InterruptedException.

Что мне не хватает?

    Executor exec1 = Executors.newFixedThreadPool(1);

    // task to be interrupted
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println("starting uninterruptible task 1");
                Thread.sleep(4000);
                System.out.println("stopping uninterruptible task 1");
            } catch (InterruptedException e) {
                assertFalse("This line should never be reached.", true);
                e.printStackTrace();
            }               
        }           
    };
    final Thread t1 = new Thread(runnable);


    // task to send interrupt
    Runnable runnable2 = new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                t1.interrupt();
                System.out.println("task 2 - Trying to stop task 1");
                Thread.sleep(5000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }               
        }           
    };
    Thread t2 = new Thread(runnable2);

    exec1.execute(t1);
            t2.start();
    t2.join();

Ответы [ 5 ]

3 голосов
/ 22 августа 2011

Ваша ошибка в том, что вы пытаетесь выполнить Thread на ThreadPool.

Этот выглядит как для работы, потому что Thread, оказывается, реализует Runnable, но поскольку поток используется только как Runnable и не запускается как Thread, вызов методов, таких как #interrupt(), не будет иметь желаемого эффекта.

Если вам все еще нужно использоватьпул потоков, вы должны вместо этого изучить использование класса, подобного FutureTask.Оберните ваш Runnable в FutureTask, а затем отправьте задачу в пул потоков.Затем, когда вы хотите прервать задачу, позвоните futureTask.cancel(true).

3 голосов
/ 22 августа 2011

Похоже, вы неправильно понимаете темы и исполнителей. Вы создаете объект с двумя потоками для двух исполняемых объектов, но запускаете только один из них (t2), t1 вы передаете Executor для запуска внутри него. Но executor не требует предоставления Thread - ему просто нужна реализация Runnable. Сам Executor является пулом потоков (обычно, но это не обязательно), и он просто создает (и пул) потоки внутри него. Он видит ваш поток так же просто, как Runnable (который реализует Thread). Таким образом, вы фактически отправляете прерывание в поток, который никогда не был запущен.

Если вы действительно хотите, чтобы ваш код работал, вы должны удалить Executor и просто явно запустить оба потока.

1 голос
/ 22 августа 2011

Проблема в том, что вы никогда не сможете точно узнать, какой поток будет использоваться Executor для выполнения вашей задачи.

Даже если вы отправили объект Thread, Исполнитель будет использовать потоксозданный фиксированным пулом потоков.Таким образом, поток со ссылкой t1 не является потоком, в котором будет выполняться ваша задача.поэтому вызов t1.interrupt() ничего не даст.

Чтобы правильно сделать это, используйте ExecutorService и submit() для отправки Runnable / Callable объекта.Это вернет Future, который предоставляет метод cancel(), который можно использовать для отмены задачи.

0 голосов
/ 22 августа 2011

Вызов Thread.interrupt не обязательно вызывает исключение InterruptedException.Он может просто установить прерванное состояние потока, которое можно опрашивать с помощью Thread.interrupted () или Thread.isInterrupted.

Подробнее см. http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#interrupt().

0 голосов
/ 22 августа 2011

Чтобы прервать поток исполнителя,

final ExecutorService exec1 = Executors.newFixedThreadPool(1);
final Future<?> f = exec1.submit(runnable);
...
f.cancel(true);
...