0

I tried to set a 1-second time limit for my SQL query in Java, using the methods: How to timeout a thread

public class App {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(1, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        try {
            // some codes to do query via SQL Server JDBC, assuming it takes 10 seconds.
            ResultSet result = statement.executeQuery();
            // some codes to print the query result
        return "Done";
        }
        catch (Exception e) {
            System.out.println();
            e.printStackTrace();
        }
    }
}

However, I found that though it prints 'Terminated' after 1 second, the program keeps running and prints the query result after 10 seconds. What's the reason why it doesn't work and how to fix it?

MTANG
  • 508
  • 5
  • 16
  • As mentioned in the question you linked, you have to check `Thread.interrupted()` inside your `call()` method. If it is set to `true` you return the method immediately and don't print/use the result anymore. – Progman Nov 12 '18 at 22:45
  • @Progman Thanks. But how would I do this. It's just a single line of code runs about 10s. (If I'm running a for loop that may run for a long time, I may check interrupted for each iteration, but this is not the case). – MTANG Nov 13 '18 at 14:48
  • If the method you are calling does not check the `Thread.interrupted()` call itself you have to wait for it to finish. But **you** can still check `Thread.interrupted()` after the long running call and decide not to do you actions you normally would do (like printing the result set). – Progman Nov 13 '18 at 14:54
  • @Progman Actually we want to raise an exception if there is a time out. (Rather than 'wait until finish and decide what to do' – MTANG Nov 13 '18 at 15:02
  • As mentioned by "Joe C" you can use `setQueryTimeout()` to set the timeout before calling `executeQuery()`. But since you said it didn't work for you, you might need to edit your question to include the full source code you have (with the `setQueryTimeout()` call) and how exactly it "isn't working". – Progman Nov 13 '18 at 15:14
  • @Progman Not sure what counts towards the setquerytimeout, t(server execution) or t(server execution) + t(send data to my local machine). Might be the case when server finishes query quickly but need some time to send my data back. – MTANG Nov 13 '18 at 15:27

3 Answers3

3

shutdownNow doesn't actually stop a thread, it merely sends a signal (an interrupt) that the Thread can act upon. Stopping a Thread in Java is tricky because while you can just kil the thread (with Thread.stop), you really shouldn't because you have no idea what state the Thread is in and what it will leave behind.

You can find more information in the documentation.

Jakg
  • 922
  • 12
  • 39
  • How could I do that with thread.stop(). Sorry that I'm new to Java. Also, will GC still work to collect the gabbage if I force to kill a thread. – MTANG Nov 13 '18 at 14:49
3

Calling cancel on a future does not guarantee that the job will be cancelled. It depends on the method checking periodically for interrupts, and then aborting if an interrupt is detected. Statement.execute() does not do that.

In your case, given you are executing a SQL statement, there is a method in the Statement class (setQueryTimeout) which achieves what you appear to be after without over-engineering timeouts by other means.

Joe C
  • 15,324
  • 8
  • 38
  • 50
-1

Another way you can approach this is by using the thread.sleep() method. I often use it when I want my program to simply pause for a short or long period of time. In the parameters, you put values in thousands that correspond to seconds. For example:

public static void main(String[] args) throws InterruptedException // Required for thread.sleep()
{
    System.out.println("Hi there.");
    Thread.sleep(2000); // Wait two seconds before running the next line of code
    System.out.println("Goodbye.");
}

This is quite basic, but can be used for more than just strings. Hope this helps.

ShaheerL
  • 61
  • 7
  • You are attempting to solve a different problem to the one the OP is asking about. The OP doesn't want to pause his program, but to stop an operation if it hasn't completed within a certain length of time. – Joe C Nov 13 '18 at 21:01
  • @JoeC Oh I see, sorry for the mistake. I'm trying to understand and teach to help myself learn at the same time. – ShaheerL Dec 15 '18 at 21:23