убивая бесконечный цикл в Java - PullRequest
5 голосов
/ 16 августа 2010

Я использую стороннюю библиотеку для обработки большого количества наборов данных. Процесс очень редко заходит в бесконечный цикл (или блокируется - не знаю почему и не могу попасть в код). Я хотел бы убить это через определенное время и перейти к следующему делу. Простой пример:

for (Object data : dataList) {
    Object result = TheirLibrary.processData(data);
    store(result);
}

processData обычно занимает максимум 1 секунду. Я хотел бы установить таймер, который убивает processData (), скажем, через 10 секунд

EDIT Я был бы признателен за фрагмент кода (я не практиковался в использовании потоков). Подход Executor выглядит полезным, но я не совсем понимаю, с чего начать. Кроме того, псевдокод для более традиционного подхода слишком общий, чтобы я мог его кодировать.

@ Стивен Шланскер - предполагает, что, если стороннее приложение не ожидает прерывания, оно не будет работать. Опять детали и примеры будут оценены

EDIT Я получил точное решение, которое я хотел от моих коллег Сэма Адамса, к которому я добавляю ответ. В нем более подробно, чем в других ответах, но я дам им обоим право голоса. Я отмечу Сэма как одобренный ответ

Ответы [ 3 ]

10 голосов
/ 16 августа 2010

Один из методов ExecutorService.invokeAll (...) принимает аргумент времени ожидания. Создайте один Callable, который вызывает библиотеку, и поместите его в список в качестве аргумента этого метода. Возвращенное будущее указывает, как оно прошло.

(Примечание: не проверено мной)

7 голосов
/ 16 августа 2010

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


РЕДАКТИРОВАТЬ: Демокод запроса

Это псевдокод, поэтому вам нужно его улучшить и расширить. Также может помочь проверка ошибок, если вызов был успешным или нет.

for (Object data : dataList) {
    Thread t = new LibThread(data);
    // store the thread somewhere with an id
    // tid and starting time tstart 
    // threads
    t.start();
    }

while(!all threads finished)
{
    for (Thread t : threads)
    {
        // get start time of thread
        // and check the timeout
        if (runtime > timeout)
        {
            t.stop();
        }
    }
}

class LibThread extends Thread {
    Object data;

    public TextThread(Object data) 
    {
        this.data = data;
    }

    public void processData() 
    {
        Object result = TheirLibrary.processData(data);
        store(result);
    }
}
2 голосов
/ 16 августа 2010

Сэм Адамс прислал мне следующий ответ, который является моим принятым

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.interrupt();
}

и myRunnableCode регулярно проверяют Thread.isInterrupted() и корректно завершают работу, если это возвращает true.

В качестве альтернативы вы можете сделать:

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.stop();
}

Но этот метод устарел, поскольку он ОПАСЕН.

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#stop() «Этот метод по сути небезопасен. Остановка потока с помощью Thread.stop заставляет его разблокировать все заблокированные мониторы (как естественное следствие непроверенного исключения ThreadDeath, распространяющегося вверх по стеку). эти мониторы были в несовместимом состоянии, поврежденные объекты становятся видимыми для других потоков, что может привести к произвольному поведению. "

Я реализовал второе, и оно делает то, что я хочу в настоящее время.

...