This question already has answers here:
Choose between ExecutorService's submit and ExecutorService's execute
(7 answers)
Closed 9 years ago.
I faced a problem about ThreadPoolExecutor.
After writing some code, I found the submit() method will eat the RuntimeException thrown by the program, but the execute() method will re-throw the RuntimeException`. I want to know the reason for this.
I recently read the source code of ThreadPoolExecutor and know the principle of a thread pool.
Now I understand how execute() method executes, but I couldn't understand how submit() method executes. I only know that the submit() method will wrap the Runnable or Callable in a FutureTask and call the execute() method:
public Future submit(Runnable runnable)
{
if(runnable == null)
{
throw new NullPointerException();
} else
{
RunnableFuture runnablefuture = newTaskFor(runnable, null);
execute(runnablefuture);
return runnablefuture;
}
}
So, my problem is: how does ThreadPoolExecutor execute FutureTask and why is the RuntimeException eaten?
If you look into newTaskFor method you'll see that RunnableFuture is in fact instance of java.util.concurrent.FutureTask. You should see the run method in this FutureTask class.
public void run() {
sync.innerRun();
}
and here is the innerRun method:
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
the exception is caught and set to task. It will be thrown wrapped into ExecutionException when you call get method of FutureTask
public V get() throws InterruptedException, ExecutionException {
return sync.innerGet();
}
Related
This question already has answers here:
Future task of ExecutorService not truly cancelling
(2 answers)
Closed 5 years ago.
I want to cancel a task submitted to ExecutorService thus allowing the corresponding thread to pick a new task from the queue.
Now this question have been answered many times on this forum.... like checking Thread.currentThread().interrupt() or catch (InterruptedException e). But if the flow of control spans across multiple methods then putting these checks makes the code clumsy. So if possible please suggest some elegant ways in java to achieve this functionality.
The problem that I'm facing is that future.cancel won't actually cancel the task. Instead it just sends an InterruptedException to the executing task and it's the task's responsibility to mark itself complete and release the thread.
So what I did is that I had to put the below block of code whenever an exception gets thrown anywhere in the execution which obviously doesn't look good !
if(e instanceof InterruptedException) {
throw e;
}
So, how to achieve this functionality in following code snippet:
public class MonitoringInParallelExp {
public static void main(String[] args) throws InterruptedException {
MyClass1 myClass1 = new MyClass1();
ExecutorService service = Executors.newFixedThreadPool(1);
Future<String> future1 = service.submit(myClass1);
Thread.sleep(2000);
System.out.println("calling cancel in Main");
future1.cancel(true);
System.out.println("finally called cancel in Main");
service.shutdown();
}
}
class MyClass1 implements Callable<String> {
#Override
public String call() throws Exception {
try{
MyClass2 myClass2 = new MyClass2();
myClass2.method2();
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("call:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method1. " + e);
}
System.out.println("returning Myclass1.method1.exit");
return "Myclass1.method1.exit";
}
}
class MyClass2 {
public void method2() throws Exception{
try{
MyClass3 myClass3 = new MyClass3();
myClass3.method3();
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("method2:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method2. " + e);
// in case the exception isn't InterruptedExceptionm, do some work here
}
}
}
class MyClass3 {
public void method3() throws Exception{
try{
Thread.sleep(10000);
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("method3:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method3. " + e);
throw new MyException();
}
}
}
class MyException extends Exception {
}
It does not matter if you interrupt the Callable or not, because at that point it's already too late
try{
MyClass2 myClass2 = new MyClass2();
myClass2.method2();
} catch (Exception e){
Your call to future1.cancel(true); after Thread.sleep(2000) does not actually cancel the ongoing task (in this case your method2 call) it only means that it should have been cancelled before it started.
The docs point that out
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
If you want to cancel a ongoing task you want to use a volatile boolean flag or something similiar.
i've been working for a while for a simple Maze project, and i got to the point where i need to use the Callable interface as a thread. After implementing and running, i've noticed that while the callable class runs in the background, i cant seem to work anything else on the background, such as to the an input.
i made a little project the emphasize the problem, see that while the callable class works for 10 seconds, i cant take any input in the meanwhile.
here is the code:
Main class
public class Main {
static ExecutorService service = null;
static Future<String> task = null;
public static void main(final String[] argv) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please enter a command");
String string = in.readLine();
while (!string.equals("exit")) {
if (!string.equals("command")) {
System.out.println("command not found");
} else {
service = Executors.newFixedThreadPool(1);
task = service.submit(new Foo());
try {
final String str;
// waits the 10 seconds for the Callable.call to finish.
str = task.get(); // this raises ExecutionException if
// thread dies
System.out.println(str);
service.shutdownNow();
} catch (final InterruptedException ex) {
ex.printStackTrace();
} catch (final ExecutionException ex) {
ex.printStackTrace();
}
}
string = in.readLine();
}
//
}
}
the callable class:
class Foo implements Callable<String> {
#Override
public String call() {
try {
// sleep for 10 seconds
Thread.sleep(10 * 1000);
} catch (final InterruptedException ex) {
ex.printStackTrace();
}
return ("Hello, World!");
}
}
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#submit(java.util.concurrent.Callable)
If you would like to immediately block waiting for a task, you can use constructions of the form result = exec.submit(aCallable).get();
That is exactly what you are doing (block the main thread waiting for a task)
The problem is str = task.get();.
According to the JavaDoc for Future#get() (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get%28%29):
Waits if necessary for the computation to complete, and then retrieves its result.
If you want the result from your Callable, you have to wait until it's finished.
Callable doesn't do anything in and of itself. It is just a convention interface. To make callable asynchronous, you need to run it in an executor. See https://blogs.oracle.com/CoreJavaTechTips/entry/get_netbeans_6 for instance.
i've noticed that while the callable class runs in the background, i cant seem to work anything else on the background
...discussion, ... problem explained...
it seems pointless to use this interface now.
I don't really know what you were trying to do, but the entire point of ExecutorService and Callable is to perform tasks in the background.
But what does "in the background" mean? It means, that while the new thread is off performing some task, the thread that submitted the task can do something else.
It looks like this:
final ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
ReturnType doSomethingInTheBackground() {
// create the task object
Callable<ReturnType> task = () -> doSomething();
// submit the task object
Future<ReturnType> future = executorService.submit(task);
doSomethingElse();
// wait for the result.
return future.get();
}
private ReturnType doSomething() { ... }
private void doSomethingElse() { ... }
The doSomethingElse() call is what makes it all worthwhile. If the calling thread doesn't have anything else to do except wait for the result (i.e., call future.get()), then you were right: There would be no point in using more than one thread. It would be simpler for the calling thread to just do the task itself.
Can you think about any reason why this code doesn't work and always outputs "finished", but the second example works without any problems. I'm using latest JDK (8u45).
public static class MyClass implements Runnable {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
System.out.println("Interrupted");
return;
}
System.out.println("Finished");
}
public static void main(String[] args) {
// spot the difference ->
ExecutorService executorService = Executors.newWorkStealingPool(4);
Future future = executorService.submit(new MyClass());
Thread.sleep(100);
future.cancel(true);
}
}
And the following example works flawlessly:
public static class MyClass implements Runnable {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
System.out.println("Interrupted");
return;
}
System.out.println("Finished");
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new MyClass());
Thread.sleep(100);
future.cancel(true);
}
}
EDIT: Added return and updated sleep times and another example.
It's simpler than I thought originally. The problem is that work-stealing-pool is internally using ForkJoinPool and ForkJoinTask doesn't support cancel(true) and therefore it's not possible to cancel task after the task is started.
See javadoc documentation (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinTask.html):
mayInterruptIfRunning - this value has no effect in the default implementation
because interrupts are not used to control cancellation.
There is no way to forcibly terminate a Thread in Java. (Twenty years ago, Java 1.0 tried to provide this, and it turned out to be unworkable; the methods which attempted to do it are deprecated with no replacement.)
You, as the author of the Runnable, are responsible for properly responding to an interrupt by cleanly terminating your own run method. In your case, you should have exited your run method in the catch-block, but you didn't; you let the method's logic continue past the catch-block. So even when the thread is interrupted, the run method's last statement is always executed.
I am writing an Spring-mvc application.
I am executing task using ThreadPoolTaskExecutor.
I have below sample code.
MyClass.java
public class MyClass {
public void startProcess() {
ThreadPoolTaskExecutor taskExecutor = //Initializing
for (int i = 1; i <= 5; i++) {
taskExecutor.execute(new MyRunnable());
// I can call taskExecutor.submit(task); also, if required
}
}
}
MyRunnable.java
public class MyRunnable implements Runnable {
#Override
public void onRun() {
try {
//Code which generates exception like below
throw new Exception("Runtime Exception");
} catch (Exception e1) {
// log or throw the exception
}
}
}
I want to notify startProcess() about the exception occurred in MyRunnable's run method.
Can any one please guide me for this.
I found below links but it is not solving my problem.
Handling exceptions from Java ExecutorService tasks
http://java.dzone.com/articles/spring-async-and-exception
Thanks.
Edit:
One more question. If I am using #Async for asynchronous call to my some other method and If I want to check for the exception occured in async method then what should I do? As async method also returns future object.
Answer for #Async question I got from here
Instead of Runnable, implement Callable. A Callable can throw an exception, and when you retrieve the result of the Callable using a Future, you will get the exception thrown as an ExecutionException:
public class MyCallable implements Callable<Void> {
public Void call() throws Exception {
try {
//Code which generates exception like below
throw new Exception("Runtime Exception");
} catch (Exception e1) {
// log or throw the exception
}
return null; // To satisfy the method signature
}
}
In MyClass:
List<Future<Void>> futures = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
Future<Void> future = taskExecutor.submit(new MyCallable());
futures.add(future);
}
// After all tasks have started, now wait for all of them to complete (they run in parallel)
// and check if there were any exceptions
for (Future<Void> future : futures) {
try {
future.get();
} catch (ExecutionException e) {
// Access the exception thrown by the different thread.
e.getCause().printStackTrace();
}
}
You can add constructor with some listener to your Thread.
Like:
ExceptionListener:
public class ExceptionListener{
public void doSomething(long threadId,Exception e){
//...e.g., notify startProcess()
}
}
MyRunnable:
public class MyRunnable implements Runnable {
private ExceptionListener listener;
private MyRunnable(ExceptionListener exception) {
this.listener = listener;
}
#Override
public void run() {
//...
listener.doSomething(Thread.currentThread().getId(),new Exception("Runtime Exception"));
//...
}
}
startProcess():
public void startProcess() {
ThreadPoolTaskExecutor taskExecutor = //Initializing
ExceptionListener listener= new ExceptionListener();
for (int i = 1; i <= 5; i++) {
taskExecutor.execute(new MyRunnable(listener();
// I can call taskExecutor.submit(task); also, if required
}
}
Or, you can use Thread.UncaughtExceptionHandler, like described here.
edited.
Clarification:
if exception occurs, I have to stop my further execution of other
processes. So I want to catch or get notified about the exception in
startProcess method. – Naman Gala 1 hour ago
Answer:
I suppose that your worker thread will have while cycle. So you can just pass volatile
boolean to each thread and set it up to true or
false in case of exception, cycle condition will be this boolean
variable. – Maksym 58 mins ago
I have a Controller class and a Monitor worker thread.
The controller thread looks something like this
public class ControllerA {
public void ControllerA(){
try{
doWork();
}
catch(OhNoException e){
//catch exception
}
public void doWork() throws OhNoException{
new Thread(new Runnable(){
public void run(){
//Needs to monitor resources of ControllerA,
//if things go wrong, it needs to throw OhNoException for its parent
}
}).start();
//do work here
}
}
Is such setup feasible? How do I throw exception to the outside of the thread?
How do I throw exception to the outside of the thread?
Couple ways you can do this. You can set a UncaughtExceptionHandler on the thread or you can use an ExecutorService.submit(Callable) and use the exception that you get from the Future.get().
The easiest way is to use the ExecutorService:
ExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
Future<Void> future = threadPool.submit(new Callable<Void>() {
public Void call() throws Exception {
// can throw OhNoException here
return null;
}
});
// you need to shut down the pool after submitting the last task
threadPool.shutdown();
try {
// this waits for your background task to finish, it throws if the task threw
future.get();
} catch (ExecutionException e) {
// this is the exception thrown by the call() which could be a OhNoException
Throwable cause = e.getCause();
if (cause instanceof OhNoException) {
throw (OhNoException)cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException)cause;
}
}
If you want to use the UncaughtExceptionHandler then you can do something like:
Thread thread = new Thread(...);
final AtomicReference throwableReference = new AtomicReference<Throwable>();
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
throwableReference.set(e);
}
});
thread.start();
thread.join();
Throwable throwable = throwableReference.get();
if (throwable != null) {
if (throwable instanceof OhNoException) {
throw (OhNoException)throwable;
} else if (throwable instanceof RuntimeException) {
throw (RuntimeException)throwable;
}
}
Runnable interface cannot throw checked exceptions or return values. In The Callable interface you can call any worker method that return values or throws exceptions. The main tasks of the monitor would be
To declare and initialize the future with the callable instance.
A getResult() method that can have a return future.get(); statement and should declare any checked exceptions in its throws clause for it to be handled by the calling code. In this way we dont have to return a null.