0

I want to implement iterative deepening (incremental tree building). This is the part of my code I will ask about:

        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Set<Callable<Integer>> callables = new HashSet<Callable<Integer>>();

        callables.add(new Callable<Integer>() {
            public Integer call() throws Exception {
                iterativeDeepening(depthLimit, board);
                return -1;
            }
        });
        callables.add(new Callable<Integer>() {
            public Integer call() throws Exception {
                Thread.sleep(500);
                return 1;
            }
        });
        try{
            executorService.invokeAny(callables, 1000, TimeUnit.MILLISECONDS);
        }catch(TimeoutException | InterruptedException ex){
            executorService.shutdown();
        }

        executorService.shutdown();

From what I read about invokeAny() with time limit it should end executing its Callable objects as soon as the deadline is reached. It works when I put long sleep instead of my function iterativeDeepening(depthLimit, board). How to make it work with my function? Below I paste the code to this function:

    public void iterativeDeepening(byte depthLimit, byte[] board){

    for(byte depth=1;depth<depthLimit;depth++){
        GameTree gameTree= new GameTree();
        byte[] tempBoard = new byte[14];
        for(byte i=0;i<14;i++){
            tempBoard[i] = board[i];
        }
        Node <byte[]> root= new Node<byte[]>(tempBoard, player);
        try {
            gameTree.buildGameTree(depth, root);
        } catch (OutOfMemoryError E) {
            gameTree.eraseGameTree(depth,root);
            System.gc();
        }

        MiniMax minimax = new MiniMax(player);
        move= minimax.selectMove(depth, root);

    }
}

If you know a better way to make it or know how to successfully stop execution of my function please let me know. I tried also a Runnable Interface mentioned in this topic: How to stop execution after a certain time in Java? but it just worked the same.

Community
  • 1
  • 1
user2923339
  • 121
  • 2
  • 10
  • If you want it to be self-contained, you can just store a variable of System.currentTimeMillis() before you enter the loop. Then check `if (System.currentTimeMillis() - startTime >= maxRunTime)` on each iteration of the loop. – Radiodef Oct 26 '13 at 19:07
  • That's not a solution because inside a loop there is a function gameTree.buildGameTree(depth, root); which itself sometimes takes longer than the deadline which is crucial. – user2923339 Oct 26 '13 at 21:50
  • You can pass the start time in as a parameter. @AndreyChaschev is probably correct that your best bet is to just check for the interrupt. Interrupting a thread does not necessarily end it prematurely without checking for the interrupt yourself. – Radiodef Oct 26 '13 at 22:02
  • I already tried with the below solution which at first I thought will be legit but it didn't work for me- maybe it's my mistake (I'll paste the code later because deadline is coming). Passing time as a parameter is very simple and great idea. I'll try it now. Thanks! – user2923339 Oct 26 '13 at 22:29
  • If checking for the interrupt isn't working the other thing you can try is to sleep for some trivial time like 1ms and catch the InterruptedException. I don't know why, but I've had good luck with that in the case of a run away thread that did not see the flag. – Radiodef Oct 26 '13 at 22:40
  • You could try using thread dump to check where it hangs. This is the right place to insert a check for interruption. – Andrey Chaschev Oct 26 '13 at 23:55
  • I've read the thread from start and updated the answer - there is no legal way to stop your logic from outside in Java. – Andrey Chaschev Oct 27 '13 at 00:01

1 Answers1

1

After the timeout is reached, the ExecutorService will try to interrupt all the currently running tasks by calling Thread.interrupt() on them. This will put each of the threads to an interrupted state. sleep() quits when this state is set.

So adding this check:

if(Thread.currentThread().interrupted()) {
    return;
}

inside your function should do the job.

A tip for you thread termination:

try{
    executorService.invokeAny(callables, 1000, TimeUnit.MILLISECONDS);
} catch(TimeoutException | InterruptedException ex){
    //... ignore
} finally {
    executorService.shutdown();
    executorService.awaitTermination(); <-- add this line if you want to wait for the computation to end
}

UPDATE

That's not a solution because inside a loop there is a function gameTree.buildGameTree(depth, root); which itself sometimes takes longer than the deadline which is crucial.

As far as I know, there is no way to interrupt such function from outside. This function should check it's state from time to time. If it's a loop, consider checking the state on some or all of the iterations.

Andrey Chaschev
  • 16,160
  • 5
  • 51
  • 68
  • No... Unfortunately it's not a loop but a recursive function which acts very weird. At the beginning (of buildGameTree(...)) I added startTime as an argument and I'm checking at the beginning if the time is over. If so- I'm returning an exception which is caught and the result is returned. Weird is that the time limit is very often exceeded even 2-3 times. I tried using both nanoTime() and currentTimeMillis() with the same result. – user2923339 Oct 27 '13 at 00:37
  • You might need to catch the exception explicitly on the top level of the thread. – Andrey Chaschev Oct 27 '13 at 00:45
  • Why not directly? Since I started to pass time as an argument I flattened those two functions. Catching looks like this: try {gameTree.buildGameTree(depth, root, startTime, timeLimit); } catch (OutOfMemoryError | Exception e) {return move;} – user2923339 Oct 27 '13 at 00:51
  • Because `invokeAny` won't propagate exceptions from your thread if there is at least one successfully finished task. In this case you won't notice anything wrong is happening. – Andrey Chaschev Oct 27 '13 at 08:26