问题是这样的,我有个程序段,但这个程序段执行的时间长短是未知的,我想用用代码控制这个程序段,如果超过了我指定的时间,我就中断那一段程序。在网上搜了下,找到如下一段超时处理的程序。二.实现方法  方法1.(原创)  实现描述:使用一个守护线程作为计时器,并且在计时结束时抛出一个未检测异常。  具体实现:  类1:守护线程类  /**
  * 本线程设置了一个超时时间
  * 该线程开始运行后,经过指定超时时间,
  * 该线程会抛出一个未检查异常通知调用该线程的程序超时
  * 在超时结束前可以调用该类的cancel方法取消计时
  * @author solonote
  */
  public class TimeoutThread extends Thread{
  /**
  * 计时器超时时间
  */
  private long timeout;
  /**
  * 计时是否被取消
  */
  private boolean isCanceled = false;
  /**
  * 当计时器超时时抛出的异常
  */
  private TimeoutException timeoutException;
  /**
  * 构造器
  * @param timeout 指定超时的时间
  */
  public TimeoutThread(long timeout,TimeoutException timeoutErr) {
  super();
  this.timeout = timeout;
  this.timeoutException = timeoutErr;
  //设置本线程为守护线程  this.setDaemon(true);
  }
  /**
  * 取消计时
  */
  public synchronized void cancel()
  {
  isCanceled = true;
  }
  /**
  * 启动超时计时器
  */
  public void run()
  {
  try {
  Thread.sleep(timeout);
  if(!isCanceled)
  throw timeoutException;
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  }
  注: 类一中的TimeoutException是下边的用户自定义类,不是java中的java.util.concurrent.TimeoutException  类2.抛出异常类,该类继承了RuntimeException,原因是run方法不能抛出已检测异常。  public class TimeoutException extends RuntimeException {
  /**
  * 序列化号
  */
  private static final long serialVersionUID = -8078853655388692688L;
  public TimeoutException(String errMessage)
  {
  super(errMessage);
  }
  }
  使用方法:  //初始化超时类  TimeoutThread t = new TimeoutThread(5000,new TimeoutException("超时"));
  try{
  t.start();
  .....要检测超时的程序段....
  t.cancel();
  }catch (TimeoutException e)
  {
  ...对超时的处理...
  }
  TimeoutException可以更换为其他未检查异常类。执行程序时,发现下面这一部分:
TimeoutThread t = new TimeoutThread(5000,new TimeoutException("超时"));
  try{
  t.start();
  .....要检测超时的程序段....
  t.cancel();
  }catch (TimeoutException e)
  {
  ...对超时的处理...
  }中的TimeoutException 我catch不到,程序不会执行我在catch中写的处理。请高手指点下。是不是因为TimeoutException 是运行时异常,所以无法捕捉? 另外像我描述的这种超时处理,大家一般是怎么处理。谢谢。

解决方案 »

  1.   

    首先按照楼主的思路来看一下这个问题。如果想catch到那个TimeoutException,要使用Future,Runnable。代码如下:public class TimeoutThread implements Runnable { private long timeout;
    private boolean isCanceled = false;
    private TimeoutException timeoutException; public TimeoutThread(long timeout, TimeoutException timeoutErr) {
    super();
    this.timeout = timeout;
    this.timeoutException = timeoutErr;
    }

    public synchronized void cancel(){
    this.isCanceled = true;
    }
    public void run() {
    try {
    Thread.sleep(timeout);
    if(!isCanceled){
    throw timeoutException;
    }
    } catch (InterruptedException e) {
    }
    }}
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;public class TimeoutTest { public static void main(String[] args) { final ExecutorService service = Executors.newFixedThreadPool(1);

    TimeoutThread timeoutThread = new TimeoutThread(5000, new TimeoutException("This my own timeout"));

    Future future = service.submit(timeoutThread);

    try {
    try {
    future.get(0l, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    if(e.getCause() instanceof TimeoutException){
    throw new TimeoutException("Timeout from 0");  //0
    }
    }
    Thread.sleep(1000);
    try {
    future.get(0l, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    if(e.getCause() instanceof TimeoutException){
    throw new TimeoutException("Timeout from 1");  //1
    }
    }
    Thread.sleep(5000);
    try {
    future.get(0l, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    if(e.getCause()instanceof TimeoutException){
    throw new TimeoutException("Timeout from 2"); //2
    }
    }
    Thread.sleep(3000);
    try {
    future.get(0l, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    if(e.getCause() instanceof TimeoutException){
    throw new TimeoutException("Timeout from 3"); //3
    }
    }
    timeoutThread.cancel();
    } catch (Exception e) {
    System.out.println(e.getMessage());
    } finally{
    service.shutdownNow();
    }
    }
    }上面的代码虽然可以利用TimeoutException来检验是否Timeout,但要每执行一阵主程序就检验一次,代码比较乱,时间控制也不精确。于是有了下面的方案:import java.util.concurrent.Callable;public class TaskThread implements Callable<Long> {

    private long taskRunningTime;
    private long taskStartTime; public Long call() throws Exception {
    taskStartTime = System.currentTimeMillis();
    try {
    Thread.sleep(2000);
    } catch (Exception e) {
    System.out.println("Task is interrupted!");
    taskRunningTime = System.currentTimeMillis() - taskStartTime;
    }
    taskRunningTime = System.currentTimeMillis() - taskStartTime;
    return taskRunningTime ;
    }}
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;public class TimeoutTest1 { public static void main(String[] args) {
    final ExecutorService service = Executors.newFixedThreadPool(2); TimeoutThread timeoutThread = new TimeoutThread(5000,
    new TimeoutException("This my own timeout"));
    TaskThread taskThread = new TaskThread(); Future timeoutFuture = service.submit(timeoutThread); long taskRunningTime;
    long taskStartTime;

    taskStartTime = System.currentTimeMillis();
    Future taskFuture = service.submit(taskThread);

    try {
    timeoutFuture.get(6000, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    if (e.getCause() instanceof TimeoutException) {
    try {
    if (taskFuture.cancel(true)) { taskRunningTime = System.currentTimeMillis() - taskStartTime;
    System.out.println("Task might be interrupted.\nTask Running Time is: "
    + taskRunningTime/1000 + " seconds."); } else {
    System.out.println("Task might be finished.\nTask Running Time is: "
    + ((Long) (taskFuture.get()))/1000 + " seconds.");
    }
    } catch (InterruptedException e1) {
    e1.printStackTrace();
    } catch (ExecutionException e1) {
    e1.printStackTrace();
    }
    }
    } finally {
    service.shutdownNow();
    }
    }}上面代码的思路是:把实际要执行任务放到那个TaskThread里。这个TaskThread是一个Callable,所以可以返回一个值给主程序。在出程序里我们用:
    timeoutFuture.get(6000, TimeUnit.MILLISECONDS);
    来判断是否Timeout,如果Timeout,我们会用:
    taskFuture.cancel(true)
    来终止TaskThread的运行。这样思路就清晰多了。
      

  2.   

    用ExecutorService.submit(Callable<T> task) 提交一个任务,返回一个Future<T>。
    用Future<T>.get(long timeout, TimeUnit unit);等任务执行完的结果,
    如果没有执行完,直接ExecutorService.shutdownNow()杀掉线程池。
      

  3.   

    ExecutorService executor = Executors.newSingleThreadExecutor();
    FutureTask<String> future = new FutureTask<String>(new Callable<String>() {// 使用Callable接口作为构造参数
    public String call() {
    //程序执行代码
    return null;
    }
    });
    executor.execute(future);
    // 在这里可以做别的任何事情
    try {
    future.get(60000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为10秒。同样可以用future.get(),不设置执行超时时间取得结果
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    } catch (TimeoutException e) {
    e.printStackTrace();
    } finally {
    executor.shutdown();
    }我使用的这个 不过发现很奇怪的问题,前几天测试的时候还是好的,今天测试的时候cpu竟然达到99%