【问题标题】:Java function ending after time has elapsedJava函数在时间过去后结束
【发布时间】:2013-01-13 02:22:16
【问题描述】:

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

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() 终止。

【问题讨论】:

  • 闻起来像你需要 TimerTask。
  • 听起来差不多。我从来没有用过。你能举个例子吗?

标签: java timer


【解决方案1】:
// 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. 不错的奖励,第二次修改它会立即返回列表。

【讨论】:

  • @CodeGuy 是啊,很乱,我才两分钟就写完了。
  • 我怎样才能得到它,以便我明确知道 foo() 是否还没有完成。现在,它打印出 foo 每次都停止。
  • 请查看编辑。我需要 foo() 来返回一个 ArrayList,而不是 void。我在初始化它的位置以及修改它并返回它的位置添加了代码。我该怎么做?
  • 我认为它需要一些自定义类。
  • @CodeGuy 我认为我刚刚提出的内容无论如何都行不通。让我再试一次。
【解决方案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);
    }
  }
}

【讨论】:

  • 谢谢...我会试一试的。但首先,这个“Throwables”是什么东西。有必要吗?
  • 没必要,你可以在其他 catch 块中做任何你想做的事情。我只是有传播我不想处理的异常的习惯。
  • 明白了。所以我运行了它,它似乎运行没有停止(直到我手动终止程序)或打印任何东西。
  • 您还需要在任务中定期检查 Thread.interrupted() 并在返回 true 时抛出 InterruptedException。
  • 嗯...所以这并不能避免手动检查的需要(就像我建议对原始问题中经过的时间做的那样)。
【解决方案3】:

这样的方法可以解决问题,但要小心:

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())都依赖于此。

【讨论】:

    【解决方案4】:

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

    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);
    

    【讨论】:

    • 我其实对 Threads 有点熟悉。我已经制作了 Runnable 类和线程。你能举个例子说明如何通过并发来完成吗?
    • 当然。裂指关节。不要复制和粘贴此代码。 :) 去编辑答案
    • 嗯...我不一定要 System.exit(0) 在这一点上,我只想结束 doComplicatedStuff() 方法....您发布的代码可以适应那个?
    • 您可以将完成的变量传递给 doComplicatedStuff 方法并不时检查它,而不是在完成状态上循环,只需休眠四秒钟,然后将其更改为 true。
    • 计算机真的不介意不断检查变量。我想他们偷偷喜欢它。检查变量的主要关注点是什么?
    猜你喜欢
    • 2015-07-14
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    相关资源
    最近更新 更多