Setting custom RejectedExecutionHandler for ThreadPoolExecutor after executing some tasks? - java

I am using Java ThreadPoolExecutor in one of my Android components. My question is that :
Is it a good practice to set RejectedExecutionHandler using setRejectedExecutionHandler() after executing some tasks to the TPE ?
I mean are there any side effects of doing this. Is it a good practice?
Edited
I am required to create a ThreadPoolManagementLibrary project in Android which can be used by other projects. Now, I need to expose public methods of TPE in my component. If I let the user set RejectedExecutionHandler then would it be a problem?

The question should be "Should we handle the RejectedExecutionException?". The answer is of course yes. Not doing so will crash the thread in which it occurs i.e. the thread submitting the task for execution, and the application will continue running in an unknown state.
The second question is "What should we do to handle this exception?". We should probably stop the application as cleanly as possible. As this is true also for other runtime exceptions (and errors, by the way), one solution is to use an UncaughtExceptionHandler. But if we want to handle the RejectedExecutionException in a specific manner, we may use a RejectedExecutionHandler. This could be used to do some specific handling before stopping the application (either directly or by throwing a new RuntimeException that will be caught by the UncaughtExceptionHandler).
The main point here is that all exceptions and errors should be handled. This is against so call "best practices", but these practices are just wrong. They were right once for single thread applications. The world has changed. A runtime exception or an error will crash the thread in which it occurs, not the application. So it MUST BE HANDLED.
Of course, if you are using a framework or an application server, the problem may be different because this server or framework will probably handle the uncaught exceptions for you.

I don't think so. Let us try to understand what a RejectedExecutionHandler does?
When you submit submit a task to the ThreadPoolExecutor then following sequence of event happens:
If there is any worker thread free which is free and can run this task.
Else it will try to move this task to the workerqueue from where a worker thread will pick up the task if it is free.
If the workerQueue is also full then it will try to create a new thread if possible(no of worker threads are less than maxPoolSize).
If all the above fails then the task is sent to the handler and the default handler throws a RejectedExecutionException.
So basically, if you allow user to set their own handler then you are giving them freedom to handle the rejected task in their own way. They should be careful while implementing it.

I would also agree with #user2120553 .
All the points #Braj Kishore mentioned are correct, but I would like to mention that if we declare our custom RejectedExecutionHandler then we would surely get a chance to retry the execution.

Related

Behavior of the single-threaded default scheduler used with Spring #Scheduled/#EnableScheduling registrar when a TaskScheduler is not setup/available

As noted in the Spring docs for EnableScheduling, when a TaskScheduler pool is not setup/available/resolvable, "a local single-threaded default scheduler will be created and used within the registrar"
Now when this happens what is the nature & behavior of this default scheduler particularly w.r.t whether or not its thread would potentially get terminated due to a failure during execution that is not caught/handled?
Is this default scheduler an instance of ThreadPoolTaskScheduler? If so then what is its default ErrorHandler strategy ? Is it that the throwable is simply logged?
Or is this default scheduler a simpler one, simply an instance of ScheduledExecutorService that is constructed from invoking Executors.html#newSingleThreadScheduledExecutor() where in as stated there, "if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks".
Thanks
Found the answers myself after looking at the Spring task scheduling source code. Sharing here for others.
For this one,
Now when this happens what is the nature & behavior of this default scheduler particularly w.r.t whether or not its thread would potentially get terminated due to a failure during execution that is not caught/handled?
Answer is as expected, it won't. User submitted tasks are decorated as a org.springframework.scheduling.support.DelegatingErrorHandlingRunnable that wraps the user Runnable, catches any exception or error thrown from it and allows an org.springframework.util.ErrorHandler to handle it. Here is the source.
For this one,
Is this default scheduler an instance of ThreadPoolTaskScheduler? If so then what is its default ErrorHandler strategy ? Is it that the throwable is simply logged?
Or is this default scheduler a simpler one, simply an instance of
ScheduledExecutorService that is constructed from invoking
Executors.html#newSingleThreadScheduledExecutor()...
Answer is its an instance of org.springframework.scheduling.concurrentConcurrentTaskScheduler that does wrap a ScheduledExecutorService constructed from invoking Executors.html#newSingleThreadScheduledExecutor().
The ErrorHandler strategy is to log the user Throwables at error level. In addition, repeated tasks will also have the user Throwable suppressed & not propagated (so that subsequent executions of the task will not be prevented) while for one shot tasks it will be propagated (re-thrown) as expected. Here is the source.
Both of the above is what i was expecting, but wanted to make sure since the nature & behavior of this default is not clearly documented. Perhaps a little more documentation might help.
Thanks

Does process have any overhead in context switching compared to threads?

A few words about what I'm planing to do. I need to create some task executor, that will poll tasks from queue and just execute code in this task. And for this I need to implement some interrupt mechanism to enable user to stop this task.
So I see two possible solutions: 1. start a pool of threads and stop them by using .destroy() method of a thread. (I will not use any shared objects) 2. Use pool of separated processes and System.exit() or kill signal to process. Option 2. looks much safer for me as I can ensure that thread killing will not lead to any concurrency problems. But I'm not sure that it won't produce a big overhead.
Also I'm not sure about JVM, if I will use separated processes, each process will be using the separated JVM, and it can bring a lot of overhead. Or not. So my question in this. Choosing a different language without runtime for worker process is possible option for me, but I still don't have enough experience with processes and don't know about overhead.
start a pool of threads and stop them by using .destroy() method of a thread. (I will not use any shared objects)
You can't stop threads on modern VMs unless said thread is 'in on it'. destroy and friends do not actually do what you want and this is unsafe. The right way is to call interrupt(). If the thread wants to annoy you and not actually stop in the face of an interrupt call, they can. The solution is to fix the code so that it doesn't do that anymore. Note that raising the interrupt flag will guaranteed stop any method that is sleeping which is specced to throw InterruptedException (sleep, wait, etc), and on most OSes, will also cause any I/O call that is currently frozen to exit by throwing an IOException, but there is no guarantee for this.
Use pool of separated processes and System.exit() or kill signal to process.
Hella expensive; a VM is not a light thing to spin up; it'll have its own copy of all the classes (even something as simple as java.lang.String and company). 10 VMs is a stretch. Whereas 1000 threads is no problem.
And for this I need to implement some interrupt mechanism to enable user to stop this task.
The real problem is that this is very difficult to guarantee. But if you control the code that needs interrupting, then usually no big deal. Just use the interrupt() mechanism.
EDIT: In case you're wondering how to do the interrupt thing: Raising the interrupt flag on a thread just raises the flag; nothing else happens unless you write code that interacts with it, or call a method that does.
There are 3 main interactions:
All things that block and are declared to throw InterruptedEx will lower the flag and throw InterruptedEx. If the flag is up and you call Thread.sleep, that will immediately_ clear the flag and throw that exception without ever even waiting. Thus, catch that exception, and return/abort/break off the task.
Thread.interrupted() will lower the flag and return true (thus, does so only once). Put this in your event loops. It's not public void run() {while (true) { ... }} or while (running) {} or whatnot, it's while (!Thread.interrupted() or possibly while (running && !Thread.interrupted9)).
Any other blocking method may or may not; java intentionally doesn't specify either way because it depends on OS and architecture. If they do (and many do), they can't throw interruptedex, as e.g. FileInputStream.read isn't specced to throw it. They throw IOException with a message indicating an abort happened.
Ensure that these 3 code paths one way or another lead to a task that swiftly ends, and you have what you want: user-interruptible tasks.
Executors framework
Java already provides a facility with your desired features, the Executors framework.
You said:
I need to create some task executor, that will poll tasks from queue and just execute code in this task.
The ExecutorService interface does just that.
Choose an implementation meeting your needs from the Executors class. For example, if you want to run your tasks in the sequence of their submission, use a single-threaded executor service. You have several others to choose from if you want other behavior.
ExecutorService executorService = Executors.newSingleThreadExecutor() ;
You said:
start a pool of threads
The executor service may be backed by a pool of threads.
ExecutorService executorService = Executors.newFixedThreadPool​( 3 ) ; // Create a pool of exactly three threads to be used for any number of submitted tasks.
You said:
just execute code in this task
Define your task as a class implementing either Runnable or Callable. That means your class carries a run method, or a call method.
Runnable task = ( ) -> System.out.println( "Doing this work on a background thread. " + Instant.now() );
You said:
will poll tasks from queue
Submit your tasks to be run. You can submit many tasks, either of the same class or of different classes. The executor service maintains a queue of submitted tasks.
executorService.submit( task );
Optionally, you may capture the Future object returned.
Future future = executorService.submit( task );
That Future object lets you check to see if the task has finished or has been cancelled.
if( future.isDone() ) { … }
You said:
enable user to stop this task
If you want to cancel the task, call Future::cancel.
Pass true if you want to interrupt the task if it has already begun execution.
Pass false if you only want to cancel the task before it has begun execution.
future.cancel( true );
You said:
looks much safer for me as I can ensure that thread killing will not lead to any concurrency problems.
Using the Executors framework, you would not be creating or killing any threads. The executor service implementation handles the threads. Your code never addresses the Thread class directly.
So no concurrency problems of that kind.
But you may have other concurrency problems if you share any resources across threads. I highly recommend reading Java Concurrency in Practice by Brian Goetz et al.
You said:
But I'm not sure that it won't produce a big overhead.
As the correct Answer by rzwitserloot explained, your approach would certainly create much more overhead that would the use of the Executors framework.
FYI, in the future Project Loom will bring virtual threads (fibers) to the Java platform. This will generally make background threading even faster, and will make practical having many thousands or even millions of non-CPU-bound tasks. Special builds available now on early-access Java 16.
ExecutorService executorService = newVirtualThreadExecutor() ;
executorService.submit( task ) ;

How can I guarantee the scheduling by ScheduledThreadPoolExecutor will not die abruptly?

I'm a newbie programmer who's grappling with this issue of ScheduledThreadPoolExecutor.
Upon some googling I got to know how to handle the exceptions from Runnable() part by using afterExecute method. Now it boils to down to this.
What if the ScheduledThreadPoolExecutor's scheduleAtFixedRate() method breaks out an error and the thread stops all of the sudden?
In other words, what if the
error is from the Executor class and not from the Runnable
implementation?
Is there any way that I can catch errors && deal with it (by restarting the whole scheduling) ?
Thank you
what if the error is from the Executor class and not from the Runnable
implementation?
The error does not come from the executor class.
Is there any way that I can catch errors && deal with it (by
restarting the whole scheduling) ?
Yes you can use different techniques to recognize an error and restart ScheduledExecutorService, but the real question should be: is that the right thing to do ?
If you can deal with the error in your Runnable, better deal with it there instead of paying the toll of restarting an Executor.

Queries on Java Future and RejectionHandler

I had some queries regarding Future usage. Please go through below example before addressing my queries.
http://javarevisited.blogspot.in/2015/01/how-to-use-future-and-futuretask-in-Java.html
The main purpose of using thread pools & Executors is to execute task asynchronously without blocking main thread. But once you use Future, it is blocking calling thread. Do we have to create separate new thread/thread pool to analyse the results of Callable tasks? OR is there any other good solution?
Since Future call is blocking the caller, is it worth to use this feature? If I want to analyse the result of a task, I can have synchronous call and check the result of the call without Future.
What is the best way to handle Rejected tasks with usage of RejectionHandler? If a task is rejected, is it good practice to submit the task to another Thread or ThreadPool Or submit the same task to current ThreadPoolExecutor again?
Please correct me if my thought process is wrong about this feature.
Your question is about performing an action when an asynchronous action has been done. Futures on the other hand are good if you have an unrelated activity which you can perform while the asynchronous action is running. Then you may regularly poll the action represented by the Future via isDone() and do something else if not or call the blocking get() if you have no more unrelated work for your current thread.
If you want to schedule an on-completion action without blocking the current thread, you may instead use CompletableFuture which offers such functionality.
CompletableFuture is the solution for queries 1 and 2 as suggested by #Holger
I want to update about RejectedExecutionHandler mechanism regarding query 3.
Java provides four types of Rejection Handler policies as per javadocs.
In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)
CallerRunsPolicy: If you have more tasks in task queue, using this policy will degrade the performance. You have to be careful since reject tasks will be executed by main thread itself. If Running the rejected task is critical for your application and you have limited task queue, you can use this policy.
DiscardPolicy: If discarding a non-critical event does not bother you, then you can use this policy.
DiscardOldestPolicy: Discard the oldest job and try to resume the last one
If none of them suits your need, you can implement your own RejectionHandler.

How to properly handle thread interrupts

I am working on an application that at some point starts a worker thread. This thread's behaviour will vary greatly depending on the parameters used to start it, but the following list of properties apply:
It will do some minor I/O operations
It will spend minor time in 3rd party libraries
It may create some worker threads for a certain subtask (these threads will not be reused after their task is finished)
It will spend most of its time crunching numbers (there are no blocking calls present)
Due to the possible long duration (5 minutes up to several hours, depending on the input), we want to be able to abort the calculation. If we choose to abort it, we no longer care about the output, and the thread is in fact wasting valuable resources as long as it keeps running. Since the code is under our control, the advised way is to use interrupts to indicate an abort.
While most examples on the web deal with a worker thread that is looping over some method, this is not the case for me (similar question here). There are also very few blocking calls in this work thread, in which case this article advises to manually check the interrupt flag. My question is: How to deal with this interrupt?
I see several options, but can't decide which is the most "clean" approach. Despite my practical example, I'm mainly interested in the "best practice" on how to deal with this.
Throw some kind of unchecked exception: this would kill the thread in a quick and easy way, but it reminds me of the ThreadDeath approach used by the deprecated Thread#stop() method, with all its related problems. I can see this approach being acceptable in owned code (due to the known logic flow), but not in library code.
Throw some kind of checked exception: this would kill the thread in a quick and easy way, and alleviates the ThreadDeath-like problems by enforcing programmers to deal with this event. However, it places a big burden on the code, requiring the exception to be mentioned everywhere. There is a reason not everything throws an InterruptedException.
Exit the methods with a "best result so far" or empty result. Because of the amount of classes involved, this will be a very hard task. If not enough care is taken, NullPointerExceptions might arise from empty results, leading to the same problems as point 1. Finding these causes would be next to impossible in large code bases.
I suggest you check Thread.currentThread().isInterrupted() periodically at points you knwo it is safe to stop and stop if it is set.
You could do this in a method which checks this flag and throws a custom unchecked exception or error.
What about a use of ExecutorService to execute the Runnable? Checkout the methods wherein you can specify the timeout. E.g.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes.
executor.shutdown();
Here Task of course implements Runnable.

Categories

Resources