3

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

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()”。

我尝试过的:我尝试在 foo() 的几乎每一行都包含条件,以查看已经过去了多少时间,如果 4 秒过去了,则返回函数。但是考虑到 foo() 的复杂程度,这显然很难在代码方面进行,因为这需要在函数的每一行上测试时间。

我的思维逻辑:我认为这应该是可能的,因为有些函数可以做这种事情,无论状态如何都会终止代码,例如 System.exit(1)。这就是想法。我希望能够从外部调用让这个函数 foo() 终止。

4

4 回答 4

5
// 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. 不错的奖励,它会在第二次修改完成后立即返回列表。
于 2013-01-13T02:38:51.730 回答
2

将其作为可运行文件提交给执行器服务,并在返回的未来调用 get 并使用所需的超时时间。然后在超时异常的 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);
    }
  }
}
于 2013-01-13T02:28:35.750 回答
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已弃用

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

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

于 2013-01-13T02:31:44.923 回答
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);
于 2013-01-13T02:23:57.490 回答