Java函数在经过一段时间后结束

时间:2013-01-13 02:22:17

标签: java timer

这就是我想要做的。给定一个函数

public void foo() {

}

我希望在经过一段时间后结束。也就是说,想象这是某种随机生成器,它必须产生满足某些困难约束的随机对象,因此在给定的时间分配下它可能成功也可能不成功。也就是说,该函数实际上可能是这样的

public void foo() {
   //task1
   while(fails) {
     //...
   }

   //task2
   while(fails2) {
      //...
   }

   //more tasks may follow, which use the data from the previous tasks to further try to satisfy difficult conditions
}

这只是一个例子。但重点是该函数包含许多while循环,许多测试用例以及大量繁重的计算。

目标:我希望能够说“运行foo(),如果已经过了4秒而foo()仍未完成,则立即停止foo()。” p>

我尝试了什么:我试图在foo()的几乎每一行都包含条件,看看已经过了多少时间,如果4秒钟过去了,则返回函数。但考虑到foo()有多复杂,这显然很难做到代码,因为这需要测试函数的每一行的时间。

我的思想逻辑:我认为这应该是可能的,因为有些函数会执行此类操作,无论状态如何都会终止代码,例如System.exit(1)。这就是主意。我希望能够从外部调用foo()函数终止。

4 个答案:

答案 0 :(得分:4)

// foo method and global variables used
private static ArrayList<Integer> foo() {
    // info class
    class Info {
        public boolean run, completed;
        public ArrayList<Integer> list;
    }
    // declare info object, list
    final Info info = new Info();
    final Object wait = new Object();
    // run a new thread
    Thread t = new Thread(
        new Runnable() {
            // run method
            @Override
            public void run() {
                // setup run
                info.run = true;
                info.completed = false;
                info.list = new ArrayList<>();
                // loop to modify list. Don't put a big piece of code that will
                // take a long time to execute in here. 
                while(info.run) {
                    // example of what you should be doing in here:
                    info.list.add(1);
                    // and if you are done modifying the list, use:
                    break;
                }
                // done modifying list
                info.completed = true;
                synchronized(wait) {
                    wait.notify();
                }
            }
        }
    );
    t.start();
    // wait for four seconds, then return list
    try {
        synchronized(wait) {
            wait.wait(4000);
        }
    } catch (InterruptedException e) { e.printStackTrace(); }
    info.run = false;
    return info.completed ? info.list : null;
}
// main method
public static void main(String[] args) {
    // get list
    ArrayList<Integer> list = foo();
    System.out.println("Done!");
}

foo()方法的作用是什么?

  1. 开始修改最终会返回的列表
  2. 如果修改此列表的时间超过四秒,它将停止修改列表并返回列表。
  3. 如果列表提前停止,它将返回null。
  4. 现在只使用局部变量!
  5. 很好的奖励,它会立即返回列表第二次修改它。

答案 1 :(得分:2)

将其作为runnable提交给执行程序服务,并使用所需的超时调用返回的返回将来。然后在超时异常的catch块中,您可以取消将来。

编辑:代码示例

import com.google.common.base.Throwables;

import java.util.concurrent.*;

public class ExecutorExample {
  private static final ExecutorService executor = Executors.newSingleThreadExecutor();

  public void example() {
    Future<String> future = executor.submit(new Callable<String>() {
      @Override
      public String call() throws Exception {
        return "Do your complicated stuff";
      }
    });

    try {
      future.get(4, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      Throwables.propagate(e);
    } catch (ExecutionException e) {
      //handle
    } catch (TimeoutException e) {
      future.cancel(true);
    }
  }
}

答案 2 :(得分:1)

这样的事情可以解决问题,但要注意:

public static void main(String[] args){
    Runnable fooRunner = new Runnable(){ public void run(){
        foo();
    }

    Thread fooThread = new Thread(fooRunner);
    fooThread.start();

    Thread.sleep(4000);

    fooThread.stop(); //warning -- this is deprecated!
}

问题在于Thread.stop is deprecated

Java中的多线程基本上是合作的努力。因为foo()可能正在操纵共享状态,可能受其当前拥有的锁的保护,所以在任意点停止它可能非常危险,并且可能导致程序中的不可预测的故障,错误等。 (实际上,由于foo的返回类型为void,因此必须在某个时刻操作某些共享状态才能存储其结果。)

该语言确实提供了一种告诉线程它应该在下一个方便点停止的方法:Thread.interrupt()Thread.interrupted()InterruptedException。您的foo()方法确实需要检查它是否定期中断;这就是它的完成方式,任何更高级别的库构造(如Future.cancel())都依赖于此。

答案 3 :(得分:0)

你必须进入编写线程代码的地狱舞台。

http://docs.oracle.com/javase/tutorial/essential/concurrency/

伪代码(在apache commons http://commons.apache.org/lang/download_lang.cgi中可用的mutableboolean)

...
final MutableBoolean finished = new MutableBoolean(false);
new Thread(new Runnable(){
    public void run() {
        doComplicatedStuff(finished);
    }
}).start();

Thread.sleep(4000);
finished.setValue(true);