How to wrap Thread with ReentrantLock into CompletableFuture call? - java

This is my current implementation which handles different file read/save operations consecutively:
public void runThread(MyThreadImpl myThreadImpl) {
synchronized (this) {
this.myThreadImpl = myThreadImpl;
notify();
}
}
synchronized public void run() {
while (true)
try {
wait();
Global.myReentrantLock.lock();
try {
try {
myThreadImpl.call();
} catch (FileException e) {
// trace e
} catch (RuntimeException e) {
// trace e
} catch (Exception e) {
// trace e
}
} finally {
Global.myReentrantLock.unlock();
}
} catch (InterruptedException e) {
// trace e
} catch (Exception e) {
// trace e
}
}
I have a problem that I don't wait for thread result before performing another operation, and I've come to a case where that is necessary.
Since I'm using Java 8, I wanted to wrap this in a CompletableFuture. How can I do this with my current implementation?

You could do the following:
Instead of storing the next job to be done as a single reference (this.myThreadImpl) that is updated once the lock is free, you could use a queue.
When a new job is added, a new CompletableFuture is created, and a reference to it is returned to the caller.
Once the job is completed, the future is completed.
Updating your code, and assuming queue is a blocking queue of type Queue<Pair<CompletableFuture<Void>, MyThreadImpl>>, you would have:
/**
* #return a Future that will complete once the passed MyThreadImpl has been run.
*/
public CompletableFuture<Void> runThread(MyThreadImpl myThreadImpl) {
Pair<CompletableFuture<Void>, MyThreadImpl> p =
new Pair<>(new CompletableFuture<>(),myThreadImpl);
queue.add(p);
return p.left;
}
public void run() {
while (true) {
try {
Pair<CompletableFuture<MyThreadImpl>, MyThreadImpl> p =
queue.take(); // will block until a job is added
try {
p.right.call();
p.left.complete(null); // Future<Void> can only be completed with null. Alternatively, it could be completed with a relevant result.
} catch (Exception e) {
p.left.completeExceptionally(e);
}
} catch (InterruptedException e) {
// trace e
}
}
}
Here, Pair just needs to be a pair-like pojo. (It could be apache commons's ImmutablePair, for example.)
Blocking queues are generally useful when stuff needs to be processed: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
Also, have you looked at ExecutorService? You could use one that is based on a single thread to execute jobs in a serial way: it's submit(Callable<> task) method is quite like runThread() defined above, as it returns a Future<Void> that will tell you when the task is done.

Related

Exception in a runnable appears to kill threadpool

I have a runnable that I want to run periodically. On a particular run, I believe the runnable encountered a null pointer, but no exception was shown on the console. After that failed run, it never runs again. I have two questions:
If there was a null pointer, why wasn't this shown on the console
How can I have the scheduled task run again in the future, even if a particular run fails?
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);
Answering your questions,
1) The reason why you do not see any kind of exception is due to the fact that the FutureTask#setException called within FutureTask#run effectively swallows it. In order to be be able to log the exception you should either create a new class the extends the ScheduledThreadPoolExecutor and override the afterExecute method like so:
#Override
protected void afterExecute(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
t = e;
}
}
if (t != null) {
t.printStackTrace();
}
}
Or directly invoke get on the returned ScheduledFuture like so:
var executor = Executors.newSingleThreadScheduledExecutor();
var future = executor.scheduleAtFixedRate(new MyRunnable(null), 1, 1, TimeUnit.SECONDS);
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
2) The easiest way of re-running the failed runnable would to do this:
while (true) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
But imho this approach is not the cleanest. Properly coding your Runnable#run method to handle exception would be a better solution.

Shut down two instances of ExecutorService

I need to properly shut down two instances of Executor Service in one method.
Here's my simplified code:
ExecutorService executor1 = Executors.newSingleThreadExecutor();
ScheduledExecutorService executor2 = Executors.newSingleThreadScheduledExecutor();
// logic here
executor1.shutdown();
executor2.shutdown();
try {
if (!executor1.awaitTermination(1, TimeUnit.SECONDS)) {
executor1.shutdownNow();
}
} catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
try {
if (!executor2.awaitTermination(1, TimeUnit.SECONDS)) {
executor2.shutdownNow();
}
} catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
InterruptedException is converted to IllegalStateException as I don't expect any interruptions here and this would mean my application went into illegal state.
I see one flaw in this solution - whenever first executor while shutting down throws exception, the second executor won't be properly closed. What should be correct approach here? How to safely close two instances of ExecutorService?
I'd rather like to avoid nested try-finally blocks, as I might need to add third executor service and code would become unmanageable.
As for a similar situation:
Apache Commons IO has a closeQuietly() that closes streams (or rather any Closeable) while ignoring any exception during close.
public void shutdownQuietly(ExecutorService executor)
{
try {
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException ex) {
/* IGNORE */
}
}
If you need those exception, you can try some slightly more evil trickery:
class MultiExecutorShutdown
{
private final List<InterrupedException> exceptions = new ArrayList<>();
public void shutdown(ExecutorService service)
{
try {
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException ex) {
exceptions.add(ex);
}
}
public Optional<InterruptedException> getLastException()
{
if (exceptions.isEmpty()) {
return Optional.empty();
} else {
return exceptions.get(exceptions.size() - 1);
}
}
public Optional<InterruptedException> getFirstException()
{
if (exceptions.isEmpty()) {
return Optional.empty();
} else {
return exceptions.get(0);
}
}
}
[...]
MultiExecutorShutdown multiShutdown = new MultiExecutorShutdown();
multiShutdown.shutdown(executor1);
multiShutdown.shutdown(executor2);
multiShutdown.shutdown(executor3);
Optional<InterruptedException> exception = multiShutdown.getLastException();
// alternative:
// Optional<InterruptedException> exception = multiShutdown.getFirstException();
if (exception.isPresent()) {
throw new IllegalStateException(exception.get());
}
If you also need the executor which failed, you can also modify MultiExecutorShutdown to keep an (ordered) map ExecutorService -> Exception.
You can also push the throw into MultiExecutorShutdown itself, making it even more usable. And finally the whole thing can --of course-- be abstracted so that it takes a functional, calls that and records any exceptions thrown.

ExecutorService.submit() not returning after submitting the task

I want to make an asynchronous call to a function and return without waiting for the result (in Java). The code I have written for the same is:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
hostNetworkSystem.updatePortGroup("Management Network", spec);
return null;
}
});
I have tried both Runnable and Callable but when I debug through the code in Eclipse, the thread gets stuck at the call() function doesn't return immediately after submitting the task.
Am I missing something here?
It gets stuck at:
hostNetworkSystem.updatePortGroup("Management Network", spec);
to be precise. The action is carried out as I can see the results, but it doesn't return from here.
For better understanding, this is how the entire call looks:
public void main()
{
try {
AsyncCall asyncCalls = new AsyncCall();
List<PortGroupData> portData = asyncCalls.updatePortGroupFuture(hostNetworkSystem, portGroupName,
portGroupData, modelType, oobmStatus, vlanID);
return portData;
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException " + e.getMessage().toString());
} catch (ExecutionException e) {
System.out.println("ExecutionException " + e.getMessage().toString());
e.printStackTrace();
} catch (Exception e) {
System.out.println("Exception " + e.getMessage().toString());
e.printStackTrace();
}
}
public void updatePortGroupFuture(final HostNetworkSystem hostNetworkSystem,
final String portGroupName, final NetworkParameters networkData, final String modelType,
final boolean oobmStatus, int vlanID) throws InterruptedException, ExecutionException, Exception
{
<some other actions>
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
hostNetworkSystem.updatePortGroup("Management Network", spec);
return null;
}
});
return;
}
Change your code as
Future<Void> future = executorService.submit(new Callable<Void>()
{
public Void call() throws Exception, TimeoutException {
System.out.println("before call");
hostNetworkSystem.updatePortGroup("Management Network", spec);
System.out.println("after call");
return null;
}
});
try{
result = future.get(5000, TimeUnit.MILLISECONDS);
}catch(TimeoutException e){
System.out.println("Time out after 5 seconds");
futureResult.cancel(true);
}catch(InterruptedException ie){
System.out.println("Error: Interrupted");
}catch(ExecutionException ee){
System.out.println("Error: Execution interrupted");
}
If you get TimeoutException, change the time out value to some big number.
Check for before call & after call statements. If you get before call and did not get after call, it implies some exception happened.
To know the exception, change submit() to execute() and catch exception.
submit() swallows exceptions. Have a look at this code
**Inside FutureTask$Sync**
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
}
}
protected void setException(Throwable t) {
sync.innerSetException(t);
}
Have a look at this SE Post and this SE question:
Choose between ExecutorService's submit and ExecutorService's execute
Try putting a sysout after submit(...) and see if that gets printed. That indicates the parent/main thread is not blocked on the call() method and returned immediately after submitting the task.
You can capture the Future returned by the submit method and add the following code after the submit method invocation:
try {
future.get();
}catch(ExecutionException ee){
System.out.println("exception >>" + ee.getMessage());
}
service.shutdown();
Since future.get is a blocking call, the thread submitting the task will wait for the async operation to complete. You will also get to know if its throwing any exceptions.
FutureTask stores the exception in a variable which will then be wrapped in a ExecutionException and thrown when get method is called. So we can get the underlying exception even when we call get() method on FutureTask

java multithreading using join and handling interrupted execptions correctly

I have implemented multithreading in my service layer and want to ensure I have dealt with all cases where the threads are properly handled. I don't want to end up with some kind of exception (such as RuntimeEx or InterruptedEx) which could leave my app in a bad state.
My code is below. Let me know if you can see any errors. Recommendations are most welcome. I'm using java 6.
public class MyRunnable implements Runnable {
private List<MyData> list;
private Person p;
public MyRunnable(List<MyData> list, Person p) {
this.list = list; // this list is passed in and cannot be null
this.p = p;
}
#Override
public void run() {
// before calling any of the services that gets data from the
// database, check if the thread has been interrupted
if (Thread.interrupted()) return;
List<TypeA> aList;
try {
aList = getTypeAFromDatabase1(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (Thread.interrupted()) return;
List<TypeB> bList;
try {
bList = getTypeBFromDatabase2(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (Thread.interrupted()) return;
List<TypeC> cList;
try {
cList = getTypeCFromSomeWebService(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
MyData d = new MyData();
d.setPerson(p);
d.setTypeA(aList);
d.setTypeB(bList);
d.setTypeC(cList);
list.add(d);
}
}
Service that uses Runnable:
#JsonOperation
public static List<MyData> getMyData(MyParams params) throws Exception {
List<Person> persons = params.getPersonList();
try {
// use synchronized list since all threads will add to this list
List<MyData> retList = Collections.synchronizedList(new ArrayList<MyData>());
List<Thread> threads = new ArrayList<Thread>();
// For each person, start a new thread. It there are any runtime
// exceptions thrown by any one thread, it will be caught by the
// bigger try catch block. In case of runtime exception, we will
// return back to the client right away but the other threads
// are still processing
try {
for (Person p : persons) {
// create a thread per person and start it
Runnable task = new MyRunnable(retList, p);
Thread worker = new Thread(task);
threads.add(worker);
worker.start();
// remember the thread for later use
threads.add(worker);
}
for (Thread thread : threads) {
// wait for all threads (by waiting on one thread at a time)
thread.join(3000); //3 seconds between checking on this thread
}
} catch (RuntimeException e) {
log.error(e);
for (Thread thread : threads) {
// try and send an interrupt to all threads so that they
// don't fetch any more data from the database
thread.interrupt();
}
throw e;
}
return retList;
} catch (Exception e) {
log.error(e);
throw e;
}
}
In most situations it is easier to use tasks instead of threads. You start with an ExecutorService, which restricts the number of threads and is shared across all service operations:
// inject with IoC framework
ExecutorService executor = Executors.newFixedThreadPool(10);
You use the method invokeAll to execute a task for each person. If the tasks do not finish within the given period, then the remaining tasks will be automatically cancelled. In this case, an exception is thrown when invoking the get method of the corresponding future. That means there is no need for additional exception handling.
public List<MyData> getMyData(MyParams params) throws Exception {
List<Callable<MyData>> tasks = new ArrayList<>();
for (Person p : persons) {
tasks.add(new Callable<MyData>() { // use Lambda in Java 8
public MyData call() {
MyData d = new MyData();
d.setPerson(p);
d.setTypeA(getTypeAFromDatabase1(p));
d.setTypeB(getTypeBFromDatabase2(p));
d.setTypeC(getTypeCFromSomeWebService(p));
return d;
}
});
}
List<MyData> result = new ArrayList<>();
for (Future<MyData> future : executor.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS)) {
result.add(future.get());
}
return result;
}
There is no need to check the interrupted state within the callable. If a blocking operation is called within one of the methods, the method will automatically abort execution with an InterruptedException or some other exception (if it is implemented correctly). It is also possible to set the interrupted state instead of throwing an exception. However, that makes less sense for methods with return values.

How to properly multi-thread a collection of independent tasks?

I'm using this code to divide up a few hundred tasks between different CPU cores.
final List<Throwable> errors = Collections.synchronizedList(Lists.<Throwable>newArrayList());
final ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (...) {
pool.execute(new Runnable() { #Override public void run() {
try {
// TASK HERE
} catch (Throwable e) {
errors.add(e);
}
}});
}
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!errors.isEmpty()) throw Exceptions.wrap(errors.get(0)); // TODO multi-exception
It works, but it's not nice.
There is no version of awaitTermination without timeout, which is what I want.
I need to do my own error collecting.
What is the proper/common way to do this?
The point of a thread pool is to reuse threads. You should create it on application startup, outside of your code that creates tasks, and inject it. There is no need to shut down the pool after adding tasks. You do that when your application is shutting down.
To run a collection of tasks, use ExecutorService.invokeAll. To get the results afterwards, call get on each of the returned Futures. It will rethrow any exception that the task threw, so you can collect it afterwards.
You can use a future to do the error handling:
final List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < 5; i++) {
futures.add(pool.submit(new Runnable() { #Override public void run() {
// TASK HERE
}}));
}
for (Future f : futures) {
try {
f.get();
} catch (ExecutionException e) {
//something bad happened in your runnable
}
}
//when you are done with the executor
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
I think you need to submit each Runnable, get a Future back, and then call get() on each Future.
When you call get(), you'll either get the result of the Runnable, or the exception that it encountered.

Categories

Resources