2010-07-13 2 views
4

У меня вопрос о потоках Java. Вот мой сценарий:Как остановить поток без метода stop()?

У меня есть поток, вызывающий метод, который может занять время. Поток держится на этом методе, пока не получу результат. Если я отправлю другой запрос этому методу таким же образом, теперь выполняются два потока (при условии, что первый не вернул результат). Но я хочу отдать приоритет последнему потоку и не хочу получать результаты от ранее начатых потоков. Итак, как я мог избавиться от предыдущих потоков, когда у меня нет метода остановки?

+0

Я действительно не понимаю, если вы хотите приоритезировать темы или действительно остановить потоки !? –

+0

не хотите расставлять приоритеты. но 2 избегайте всех предыдущих ... – bandit

ответ

2

Вы можете: interrupt a Thread, его цепочка выполнения чаще всего будет вызывать InterruptedException (см. Специальные случаи в the documentation).

5

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

public class MyThread extends Thread { 
    private volatile boolean running = true; 

    public void stop() { 
     running = false; 
    } 

    public void run() { 
     while (running) { 
     // do your things 
     }  
    } 
} 

Таким образом, вы можете greacefully прекратить поток, то есть без выбрасывания InterruptedException.

+1

Это было бы чище, если * вещи * находятся в цикле или прерываются от метода 'run()'. Кроме того, вы должны добавить модификатор 'volatile' в' running'. –

+0

@streetpc: Спасибо, действительно забыл ключевое слово 'volatile'. И обычно длинные «вещи» уже находятся в цикле, поэтому вы можете объединить циклы, чтобы также учитывать состояние «running». –

+0

Небольшая вещь; это boolean, а не bool, в Java –

4

Лучший способ действительно зависит от того, что делает этот метод. Если он чего-то ждет, вероятность того, что interrupt приведет к прерыванию, которое вы обрабатываете и выполняете чистое завершение. Если он делает что-то занят, он не будет:

class Scratchpad { 
    public static void main(String[] a) { 
     Thread t = new Thread(new Runnable() { 
      public void run() {doWork();} 
     }); 
     t.start(); 

     try { 
      Thread.sleep(50); 
     } catch (InterruptedException ie) {} 

     t.interrupt(); 
    } 

    private static void doWork() { 
     for (long i = 1; i != 0; i *=5); 
    } 
} 

В приведенном выше случае, единственным жизнеспособным решением действительно является переменной флаг, чтобы вырваться из петли рано на отмене, ала @inflagranti.

Другим вариантом для архитектуры, управляемой событиями, является ядовитая таблетка: если ваш метод ожидает очереди блокировки для нового элемента, тогда вы можете иметь глобальный постоянный элемент, называемый «ядовитой таблеткой», который при потреблении (из очереди) вы убиваете нить:

try { 
    while(true) { 
     SomeType next = queue.take(); 
     if (next == POISON_PILL) { 
      return; 
     } 
     consume(next); 
    } 
} catch //... 

EDIT:

похоже, что вы действительно хотите это executor service. Когда вы отправляете задание в службу исполнителя, вы возвращаете Future, который вы можете использовать для отслеживания результатов и отмены задания.

+0

На самом деле поток ждет результатов поиска от twitter, do u думаю, что прерывание будет работать? – bandit

0

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

С одной стороны, так же, как выход вы можете иметь переменный де-приоритеты, которые, когда установлено, помещает ваш поток в сон на 100 мс на каждой итерации. Это эффективно остановило бы его, пока ваша другая нить искала, а затем, когда вы переориентируете его, он вернется на полную скорость.

Однако, это немного неряшливо. Так как вы только хотите, чтобы одна вещь работала, но вы хотите, чтобы она не забывала обрабатывать другие, когда приоритет сделан, вы можете поместить свою обработку в класс с методом .process(), который вызывается повторно. Если вы хотите приостановить обработку этого запроса, вы просто перестаете вызывать .process на этом объекте некоторое время.

Таким образом вы можете реализовать стек таких объектов, и ваш поток просто выполнит stack.peek(). Process(); каждая итерация, поэтому нажатие новой, более важной задачи на стек автоматически остановит любую предыдущую задачу от работы.

Это приводит к гораздо более гибкому планированию - например, вы могли бы вернуть процесс process(), если ему нечего делать, и в этот момент ваш планировщик может перейти к следующему элементу в стеке и попробовать его «процесс»(), давая вам несколько серьезных задач в одном потоке без перенапряжения ваших ресурсов (сеть, я предполагаю)

0

Существует setPriority(int) метод для Thread. Вы можете установить приоритет первого потока следующим образом:

Thread t = new Thread(yourRunnable); 
t.start(); 
t.setPriority(Thread.MIN_PRIORITY); // The range goes from 1 to 10, I think 

Но это не будет убивать вашу нить. Если у вас есть только два потока, использующих ваш runnable, то это хорошее решение. Но если вы создаете потоки в цикле, и вы всегда устанавливаете приоритет последнего потока на минимум, вы получите много потоков.
Если это то, что приложение собирается сделать, взгляните на ThreadPool. Это не существующий класс в Java API. Вы создадите один самостоятельно.
A ThreadPool - еще один Thread, который управляет всеми остальными Threads так, как вы хотите. Вы можете установить максимальное количество работающих потоков. И в этом ThreadPool вы можете реализовать систему, которая автоматически управляет приоритетом потока. Например: вы можете сделать более старые темы более приоритетными, чтобы вы могли их закончить.

Итак, если вы знаете, как работать с ThreadPool, это может быть очень интересно.

0

Согласно API java.lang.Thread, вы должны использовать метод interrupt() и проверить флаг isInterrupted(), пока выполняете отложенную операцию. Такой подход позволяет иметь дело с разного рода «ожидания» ситуаций:
1. ожидания(), присоединиться() и сна() методы будут бросать InterruptedExcetion после вызова метода interrupt()
2. Если поток заблокирован java.nio.channels.Selector он закончит селектор
3. Если вы ожидаете, что поток ввода-вывода получит ClosedByInterruptException, но в этом случае ваш объект ввода-вывода должен реализовать интерфейс InterruptibleChannel.

Если это невозможно прервать это действие общим способом, вы можете просто отказаться от предыдущего потока и получить результаты от нового. Вы можете сделать это с помощью java.util.concurrent.Future и java.util.concurrent.ExecutorService.

Cosider следующий фрагмент кода:

public class RequestService<Result> { 

private ExecutorService executor = Executors.newFixedThreadPool(3); 

private Future<Result> result; 

    public Future<Result> doRequest(){ 
    if(result !=null){ 
     result.cancel(true); 
    } 
    result = executor.submit(new Callable<Result>() { 
     public Result call() throws Exception { 
      // do your long-running service call here 
     } 
    }); 
    return result; 
    } 

} 

Future объект здесь представляет собой результат вызова службы. Если вы вызываете метод doRequest еще раз, он пытается отменить предыдущую задачу, а затем попытаться отправить новый запрос. Поскольку пул потоков содержит более одного потока, вам не придется ждать, пока предыдущий запрос не будет отменен. Новый запрос отправляется немедленно, и метод возвращает вам новый результат запроса.

Смежные вопросы