Best practice for interrupting threads longer than a threshold

I am using the Java ExecutorService framework to submit invoked tasks for execution. These tasks interact with the web service, and the web service timeout is applied for 5 minutes. However, I saw that in some cases the timeout is ignored and the thread freezes when the API is called, so I want to cancel all tasks that take longer than they say, 5 minutes.

I currently have a list of futures and I iterate over them and call future.get until all tasks are complete. Now I saw that the overloaded future.get method takes a timeout and gives a timeout when the task does not end in this window. So I thought of an approach in which I do future.get () with a timeout, and in the case of a TimeoutException, I do future.cancel (true) to make sure this task is aborted.

My main questions
1. Does a timeout result in a better way to solve this problem?
2. Is there a chance that I am waiting with a get call on a task that has not yet been placed in the thread pool (it is not an active worker). In this case, can I complete the thread, which, when it starts, can complete within the required time period?

Any suggestions would be greatly appreciated.

+4
source share
4 answers

Does a timeout work out the best way to solve this problem?

Yes, this is great for get(timeout) for a Future object, if the task that the future indicates is already running, it will return immediately. If the task has not yet been completed or is being executed, it will wait for the timeout to end and is good practice.

Is it likely that I'm waiting with a get call on a task that has not yet been placed in the thread pool (is not an active worker)

You get a Future object only when you place the task in the thread pool, so it is not possible to call get() on the task without putting it in the thread pool. Yes, it is likely that the task is not yet occupied by a free worker.

0
source
  • Does a timeout work out the best way to solve this problem?

    • This is not enough. For example, if your task is not designed to respond to an interrupt, it will continue to run or be blocked.
  • Is it likely that I am waiting with a get call on a task that has not yet been placed in the thread pool (it is not an active worker). In this case, can I complete the thread, which, when it starts, can complete within the required time period?

    • Yes, you can stop canceling as a task that will never be started if your thread pool is not configured correctly

The following code snippet may be one way in which your task can respond to an interrupt when your task contains a lock without an interrupt. Also, it does not cancel a task whose launch is not scheduled. The idea here is to override the interrupt method and close running tasks, for example, close sockets, database connections, etc. This code is not perfect, and you need to make changes as required, handle exceptions, etc.

 class LongRunningTask extends Thread { private Socket socket; private volatile AtomicBoolean atomicBoolean; public LongRunningTask() { atomicBoolean = new AtomicBoolean(false); } @Override public void interrupt() { try { //clean up any resources, close connections etc. socket.close(); } catch(Throwable e) { } finally { atomicBoolean.compareAndSet(true, false); //set the interupt status of executing thread. super.interrupt(); } } public boolean isRunning() { return atomicBoolean.get(); } @Override public void run() { atomicBoolean.compareAndSet(false, true); //any long running task that might hang..for instance try { socket = new Socket("0.0.0.0", 5000); socket.getInputStream().read(); } catch (UnknownHostException e) { } catch (IOException e) { } finally { } } } //your task caller thread //map of futures and tasks Map<Future, LongRunningTask> map = new HashMap<Future, LongRunningTask>(); ArrayList<Future> list = new ArrayList<Future>(); int noOfSubmittedTasks = 0; for(int i = 0; i < 6; i++) { LongRunningTask task = new LongRunningTask(); Future f = execService.submit(task); map.put(f, task); list.add(f); noOfSubmittedTasks++; } while(noOfSubmittedTasks > 0) { for(int i=0;i < list.size();i++) { Future f = list.get(i); LongRunningTask task = map.get(f); if (task.isRunning()) { /* * This ensures that you process only those tasks which are run once */ try { f.get(5, TimeUnit.MINUTES); noOfSubmittedTasks--; } catch (InterruptedException e) { } catch (ExecutionException e) { } catch (TimeoutException e) { //this will call the overridden interrupt method f.cancel(true); noOfSubmittedTasks--; } } } } execService.shutdown(); 
+2
source

The approach you are talking about is fine. But most importantly, before setting a timeout threshold, you need to know what is the ideal thread pool size and timiout for your environment. Conduct a stress test to see if the thread of the workflows that you configured as part of Threadpool is OK or not. And it can even reduce the timeout value. Therefore, this test is the most important, I feel.

The get timeout is fine, but you must add to cancel the task if it throws a TimeoutException. And if you correctly perform the above test and set the thread pool size and timeout value perfectly, than you might not even need to cancel tasks from the outside (but you can use this as a backup). And yes, sometimes when you cancel a task, you may end up canceling a task that has not yet been selected by the Contractor.

0
source

You can, of course, cancel the task using

task.cancel (true)

This is completely legal. But this will interrupt the thread if it is "RUNNING" .

If the thread is waiting to receive an inline lock, then the interrupt request has no effect other than setting the thread's interrupt status. In this case, you cannot do anything to stop it. For an interrupt to occur, the thread must exit the “blocked” state, acquiring the lock it was expecting (which may take more than 5 minutes). This is a limitation of the use of "built-in lock".

However, you can use explicit lock classes to solve this problem. To do this, you can use the "lockInterruptibly" method of the "Lock" interface. "lockInterruptibly" will allow the thread to try to obtain a lock, while remaining dependent on the interrupt. Here is a small example for this:

 public void workWithExplicitLock()throws InterruptedException{ Lock lock = new ReentrantLock(); lock.lockInterruptibly()(); try { // work with shared object state } finally { lock.unlock(); } 

}

0
source

Source: https://habr.com/ru/post/1499741/


All Articles