我想运行一个线程一段固定的时间。如果在该时间内没有完成,我想要终止它,抛出一些异常,或者以某种方式处理它。怎样才能做到呢?
我从这篇文章中找到了一种方法
是在线程的run()方法中使用一个TimerTask。
有没有更好的解决方案?
编辑:添加赏金,因为我需要一个更明确的答案。下面给出的ExecutorService代码没有解决我的问题。为什么我应该在执行(一些代码-我没有处理这段代码)后睡觉()?如果代码完成并且sleep()被中断,那怎么可能是timeOut呢?
The task that needs to be executed is not in my control. It can be any piece of code. The problem is this piece of code might run into an infinite loop. I don't want that to happen. So, I just want to run that task in a separate thread. The parent thread has to wait till that thread finishes and needs to know the status of the task (i.e whether it timed out or some exception occured or if its a success). If the task goes into an infinite loop, my parent thread keeps on waiting indefinitely, which is not an ideal situation.
我给你一段代码,它展示了如何解决这个问题的方法。
例如,我正在读取一个文件。
您可以将此方法用于另一个操作,但需要实现kill()方法,以便主操作将被中断。
希望能有所帮助
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* Main class
*
* @author el
*
*/
public class Main {
/**
* Thread which perform the task which should be timed out.
*
* @author el
*
*/
public static class MainThread extends Thread {
/**
* For example reading a file. File to read.
*/
final private File fileToRead;
/**
* InputStream from the file.
*/
final private InputStream myInputStream;
/**
* Thread for timeout.
*/
final private TimeOutThread timeOutThread;
/**
* true if the thread has not ended.
*/
boolean isRunning = true;
/**
* true if all tasks where done.
*/
boolean everythingDone = false;
/**
* if every thing could not be done, an {@link Exception} may have
* Happens.
*/
Throwable endedWithException = null;
/**
* Constructor.
*
* @param file
* @throws FileNotFoundException
*/
MainThread(File file) throws FileNotFoundException {
setDaemon(false);
fileToRead = file;
// open the file stream.
myInputStream = new FileInputStream(fileToRead);
// Instantiate the timeout thread.
timeOutThread = new TimeOutThread(10000, this);
}
/**
* Used by the {@link TimeOutThread}.
*/
public void kill() {
if (isRunning) {
isRunning = false;
if (myInputStream != null) {
try {
// close the stream, it may be the problem.
myInputStream.close();
} catch (IOException e) {
// Not interesting
System.out.println(e.toString());
}
}
synchronized (this) {
notify();
}
}
}
/**
* The task which should be timed out.
*/
@Override
public void run() {
timeOutThread.start();
int bytes = 0;
try {
// do something
while (myInputStream.read() >= 0) {
// may block the thread.
myInputStream.read();
bytes++;
// simulate a slow stream.
synchronized (this) {
wait(10);
}
}
everythingDone = true;
} catch (IOException e) {
endedWithException = e;
} catch (InterruptedException e) {
endedWithException = e;
} finally {
timeOutThread.kill();
System.out.println("-->read " + bytes + " bytes.");
isRunning = false;
synchronized (this) {
notifyAll();
}
}
}
}
/**
* Timeout Thread. Kill the main task if necessary.
*
* @author el
*
*/
public static class TimeOutThread extends Thread {
final long timeout;
final MainThread controlledObj;
TimeOutThread(long timeout, MainThread controlledObj) {
setDaemon(true);
this.timeout = timeout;
this.controlledObj = controlledObj;
}
boolean isRunning = true;
/**
* If we done need the {@link TimeOutThread} thread, we may kill it.
*/
public void kill() {
isRunning = false;
synchronized (this) {
notify();
}
}
/**
*
*/
@Override
public void run() {
long deltaT = 0l;
try {
long start = System.currentTimeMillis();
while (isRunning && deltaT < timeout) {
synchronized (this) {
wait(Math.max(100, timeout - deltaT));
}
deltaT = System.currentTimeMillis() - start;
}
} catch (InterruptedException e) {
// If the thread is interrupted,
// you may not want to kill the main thread,
// but probably yes.
} finally {
isRunning = false;
}
controlledObj.kill();
}
}
/**
* Start the main task and wait for the end.
*
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
long start = System.currentTimeMillis();
MainThread main = new MainThread(new File(args[0]));
main.start();
try {
while (main.isRunning) {
synchronized (main) {
main.wait(1000);
}
}
long stop = System.currentTimeMillis();
if (main.everythingDone)
System.out.println("all done in " + (stop - start) + " ms.");
else {
System.out.println("could not do everything in "
+ (stop - start) + " ms.");
if (main.endedWithException != null)
main.endedWithException.printStackTrace();
}
} catch (InterruptedException e) {
System.out.println("You've killed me!");
}
}
}
问候
不久前,我为此创建了一个helper类。伟大的工作:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* TimeOut class - used for stopping a thread that is taking too long
* @author Peter Goransson
*
*/
public class TimeOut {
Thread interrupter;
Thread target;
long timeout;
boolean success;
boolean forceStop;
CyclicBarrier barrier;
/**
*
* @param target The Runnable target to be executed
* @param timeout The time in milliseconds before target will be interrupted or stopped
* @param forceStop If true, will Thread.stop() this target instead of just interrupt()
*/
public TimeOut(Runnable target, long timeout, boolean forceStop) {
this.timeout = timeout;
this.forceStop = forceStop;
this.target = new Thread(target);
this.interrupter = new Thread(new Interrupter());
barrier = new CyclicBarrier(2); // There will always be just 2 threads waiting on this barrier
}
public boolean execute() throws InterruptedException {
// Start target and interrupter
target.start();
interrupter.start();
// Wait for target to finish or be interrupted by interrupter
target.join();
interrupter.interrupt(); // stop the interrupter
try {
barrier.await(); // Need to wait on this barrier to make sure status is set
} catch (BrokenBarrierException e) {
// Something horrible happened, assume we failed
success = false;
}
return success; // status is set in the Interrupter inner class
}
private class Interrupter implements Runnable {
Interrupter() {}
public void run() {
try {
Thread.sleep(timeout); // Wait for timeout period and then kill this target
if (forceStop) {
target.stop(); // Need to use stop instead of interrupt since we're trying to kill this thread
}
else {
target.interrupt(); // Gracefully interrupt the waiting thread
}
System.out.println("done");
success = false;
} catch (InterruptedException e) {
success = true;
}
try {
barrier.await(); // Need to wait on this barrier
} catch (InterruptedException e) {
// If the Child and Interrupter finish at the exact same millisecond we'll get here
// In this weird case assume it failed
success = false;
}
catch (BrokenBarrierException e) {
// Something horrible happened, assume we failed
success = false;
}
}
}
}
它的名称是这样的:
long timeout = 10000; // number of milliseconds before timeout
TimeOut t = new TimeOut(new PhotoProcessor(filePath, params), timeout, true);
try {
boolean sucess = t.execute(); // Will return false if this times out
if (!sucess) {
// This thread timed out
}
else {
// This thread ran completely and did not timeout
}
} catch (InterruptedException e) {}
假设线程代码不在你的控制范围内:
根据上面提到的Java文档:
What if a thread doesn't respond to Thread.interrupt?
In some cases, you can use application specific tricks. For example,
if a thread is waiting on a known socket, you can close the socket to
cause the thread to return immediately. Unfortunately, there really
isn't any technique that works in general. It should be noted that in
all situations where a waiting thread doesn't respond to
Thread.interrupt, it wouldn't respond to Thread.stop either. Such
cases include deliberate denial-of-service attacks, and I/O operations
for which thread.stop and thread.interrupt do not work properly.
底线:
确保所有线程都可以被中断,否则你需要特定的线程知识——比如设置一个标志。也许你可以要求将任务连同停止任务所需的代码一起交给你——用stop()方法定义一个接口。您还可以在停止任务失败时发出警告。