Answers:
您可以使用执行器:
ExecutorService executor = Executors.newCachedThreadPool();
Callable<Object> task = new Callable<Object>() {
public Object call() {
return something.blockingMethod();
}
};
Future<Object> future = executor.submit(task);
try {
Object result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
// handle the timeout
} catch (InterruptedException e) {
// handle the interrupts
} catch (ExecutionException e) {
// handle other exceptions
} finally {
future.cancel(true); // may or may not desire this
}
如果future.get
5秒钟后仍未返回,则抛出TimeoutException
。可以以秒,分钟,毫秒为单位配置超时,也可以将其配置为单位TimeUnit
。
有关更多详细信息,请参见JavaDoc。
BlockingMethodCallable
的构造函数接受您要传递给它的参数blockingMethod()
并将其存储为成员变量(可能是最终变量)。然后在内部call()
将这些参数传递给blockMethod()
。
future.cancel(true)
-类型Future <Object>中的方法cancel(boolean)不适用于参数()
您可以将调用包装在中,FutureTask
并使用get()的超时版本。
参见http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html
还有一个使用jcabi-aspects库的AspectJ解决方案。
@Timeable(limit = 30, unit = TimeUnit.MINUTES)
public Soup cookSoup() {
// Cook soup, but for no more than 30 minutes (throw and exception if it takes any longer
}
它不会更加简洁,但是您必须依靠AspectJ并在构建生命周期中引入它。
有一篇文章进一步解释了它:限制Java方法执行时间
人们尝试以多种方式实现这一点真的很棒。但事实是,没有办法。
大多数开发人员会尝试将阻塞调用放在另一个线程中,并设置一个未来或某个计时器。但是Java中没有办法从外部停止线程,更不用说一些非常具体的情况了,例如Thread.sleep()和Lock.lockInterruptably()方法,这些方法显式地处理线程中断。
所以实际上您只有3个通用选项:
将阻塞调用放在新线程上,如果时间到了,您就继续前进,让该线程挂起。在这种情况下,您应确保将线程设置为Daemon线程。这样,线程不会阻止您的应用程序终止。
使用非阻塞Java API。因此,例如对于网络,请使用NIO2并使用非阻塞方法。要从控制台读取,请在阻止等之前使用Scanner.hasNext()。
如果阻塞调用不是IO,而是逻辑,那么您可以重复检查Thread.isInterrupted()
以检查它是否在外部中断,并thread.interrupt()
在阻塞线程上进行另一个线程调用
如果您真的想了解它在Java中的工作原理,那么请仔细阅读这些基础知识。它实际上讨论了那些特定的限制和场景,以及如何在其中一堂讲座中探讨这些限制和场景。
我个人尝试在不使用阻塞调用的情况下进行编程。例如,有一些工具包,例如Vert.x,可以非常轻松,高效地以非阻塞方式异步执行IO,而无需进行IO操作。
希望对您有所帮助
Thread thread = new Thread(new Runnable() {
public void run() {
something.blockingMethod();
}
});
thread.start();
thread.join(2000);
if (thread.isAlive()) {
thread.stop();
}
注意,不建议使用stop,更好的选择是设置一些易失性布尔标志,在blockingMethod()中检查并退出,如下所示:
import org.junit.*;
import java.util.*;
import junit.framework.TestCase;
public class ThreadTest extends TestCase {
static class Something implements Runnable {
private volatile boolean stopRequested;
private final int steps;
private final long waitPerStep;
public Something(int steps, long waitPerStep) {
this.steps = steps;
this.waitPerStep = waitPerStep;
}
@Override
public void run() {
blockingMethod();
}
public void blockingMethod() {
try {
for (int i = 0; i < steps && !stopRequested; i++) {
doALittleBit();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void doALittleBit() throws InterruptedException {
Thread.sleep(waitPerStep);
}
public void setStopRequested(boolean stopRequested) {
this.stopRequested = stopRequested;
}
}
@Test
public void test() throws InterruptedException {
final Something somethingRunnable = new Something(5, 1000);
Thread thread = new Thread(somethingRunnable);
thread.start();
thread.join(2000);
if (thread.isAlive()) {
somethingRunnable.setStopRequested(true);
thread.join(2000);
assertFalse(thread.isAlive());
} else {
fail("Exptected to be alive (5 * 1000 > 2000)");
}
}
}
试试这个。更简单的解决方案。保证if块在规定时间内没有执行。该过程将终止并引发异常。
public class TimeoutBlock {
private final long timeoutMilliSeconds;
private long timeoutInteval=100;
public TimeoutBlock(long timeoutMilliSeconds){
this.timeoutMilliSeconds=timeoutMilliSeconds;
}
public void addBlock(Runnable runnable) throws Throwable{
long collectIntervals=0;
Thread timeoutWorker=new Thread(runnable);
timeoutWorker.start();
do{
if(collectIntervals>=this.timeoutMilliSeconds){
timeoutWorker.stop();
throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
}
collectIntervals+=timeoutInteval;
Thread.sleep(timeoutInteval);
}while(timeoutWorker.isAlive());
System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
}
/**
* @return the timeoutInteval
*/
public long getTimeoutInteval() {
return timeoutInteval;
}
/**
* @param timeoutInteval the timeoutInteval to set
*/
public void setTimeoutInteval(long timeoutInteval) {
this.timeoutInteval = timeoutInteval;
}
}
例如:
try {
TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
Runnable block=new Runnable() {
@Override
public void run() {
//TO DO write block of code
}
};
timeoutBlock.addBlock(block);// execute the runnable block
} catch (Throwable e) {
//catch the exception here . Which is block didn't execute within the time limit
}
我在这里给您完整的代码。可以使用您的方法来代替我要调用的方法:
public class NewTimeout {
public String simpleMethod() {
return "simple method";
}
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Callable<Object> task = new Callable<Object>() {
public Object call() throws InterruptedException {
Thread.sleep(1100);
return new NewTimeout().simpleMethod();
}
};
Future<Object> future = executor.submit(task);
try {
Object result = future.get(1, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException ex) {
System.out.println("Timeout............Timeout...........");
} catch (InterruptedException e) {
// handle the interrupts
} catch (ExecutionException e) {
// handle other exceptions
} finally {
executor.shutdown(); // may or may not desire this
}
}
}
假设blockingMethod
只是睡了几毫秒:
public void blockingMethod(Object input) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我的解决方案是使用wait()
并synchronized
像这样:
public void blockingMethod(final Object input, long millis) {
final Object lock = new Object();
new Thread(new Runnable() {
@Override
public void run() {
blockingMethod(input);
synchronized (lock) {
lock.notify();
}
}
}).start();
synchronized (lock) {
try {
// Wait for specific millis and release the lock.
// If blockingMethod is done during waiting time, it will wake
// me up and give me the lock, and I will finish directly.
// Otherwise, when the waiting time is over and the
// blockingMethod is still
// running, I will reacquire the lock and finish.
lock.wait(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
所以你可以更换
something.blockingMethod(input)
至
something.blockingMethod(input, 2000)
希望能帮助到你。