Как каждый останавливает поток без остановки () метод?

У меня есть вопрос о потоках Java. Вот мой сценарий:

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

5
задан i_am_jorf 13 July 2010 в 17:06
поделиться

6 ответов

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

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.

Другой вариант для событийно-управляемых архитектур - это poison-pill: если ваш метод ожидает нового элемента в блокирующей очереди, то вы можете иметь глобальный постоянный элемент под названием "poison-pill", который при потреблении (dequeued) убивает поток:

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

EDIT:

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

4
ответ дан 13 December 2019 в 19:20
поделиться

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

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

   public void stop() {
      running = false;
   }

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

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

5
ответ дан 13 December 2019 в 19:20
поделиться

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

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

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

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

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

0
ответ дан 13 December 2019 в 19:20
поделиться

Вы можете ] interrupt Thread, его цепочка выполнения большую часть времени будет вызывать InterruptedException (см. особые случаи в документации ).

2
ответ дан 13 December 2019 в 19:20
поделиться

Существует метод 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. Вам придется создать его самостоятельно.
ThreadPool - это еще один Thread, который управляет всеми другими Threads так, как вы хотите. Вы можете установить максимальное количество запущенных потоков. И в этом ThreadPool вы можете реализовать систему, которая автоматически управляет приоритетом потоков. Например: вы можете сделать так, чтобы старые потоки получали больший приоритет, чтобы вы могли правильно их завершать.

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

0
ответ дан 13 December 2019 в 19:20
поделиться

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

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

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

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 еще раз, он попытается отменить предыдущую задачу, а затем попытается отправить новый запрос. Поскольку пул потоков содержит более одного потока, вам не придется ждать, пока предыдущий запрос не будет отменен. Новый запрос отправляется немедленно, и метод возвращает вам новый результат запроса.

0
ответ дан 13 December 2019 в 19:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: