So I am attempting to start a new thread from within a thread.
i.e.
function(update):
under certain conditions:
add a new thread running same service as current
Ideally I would like the new thread to run and my current thread to continue executing.
Instead, a new thread is created but only when it is completed does my host thread continue again.
Ideally I need it to execute concurrently, where adding a new thread has the same effect as adding a thread from my originating class.
How can i do this with executor service?
I'm currently initialising as follows:
ExecutorService executorService = Executors.newFixedThreadPool(100);
Add thread function:
final SimulatedAnnealingCallable simulatedAnnealingCallable =
new SimulatedAnnealingCallable(this, schedule);
final Future<Schedule> future = executorService.submit(simulatedAnnealingCallable);
try {
future.get();
} catch (ExecutionException ex) {
ex.getCause().printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
Shutdown occurs later
The reason is that you are blocking your main thread in the future.get().
what actually happens is that your main thread starts a new future task with the executor and than you block the main thread by telling it to wait for the results of the executing task.
one way to handle this is not waiting for the future to complete and instead add functionality to let you know the task has completed using callable.
for example
public interface CompletedTask {
void completed(boolean succes);
}
// change SimulatedAnnealingCallable to receive CompletedTask in constructor
// and call the instanc's completed method
public LogicClass implements CompletedTask {
private void someFunc() {
final SimulatedAnnealingCallable simulatedAnnealingCallable =
new SimulatedAnnealingCallable(this, schedule);
executorService.submit(simulatedAnnealingCallable);
}
public void completed(boolean succes) {
System.out.println("task is completed with " + success);
}
}
HTH,
Gal
Related
We used multiple thread groups in projects for parallel execution like below
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
Here my question is how to terminate other thread groups when exception comes in any one of the thread group.
thanks.
One option is to have a separate service which
tracks the relevant threadpools
tracks an exception flag
you delegate task submission to so it can wrap Runnables in a try-catch which sets the exception flag to true
periodically checks if the exception flag is true and, if so, attempts to shutdown all relevant threadpools
For example you could have something like below.
public class ThreadpoolService {
private final AtomicBoolean threadpoolException = new AtomicBoolean(false);
private final Set<ExecutorService> threadPools = new HashSet<>();
private final ScheduledExecutorService tracker = Executors.newSingleThreadScheduledExecutor();
public ThreadpoolService() {
// Start a thread tracking if an exception occurs in the threadpools, and if so attempts to shut them down
tracker.scheduleAtFixedRate(() -> {
if (threadpoolException.get()) {
shutdownThreadPools();
}
// Run the tracker every second, with an initial delay of 1 second before the first run
}, 1000, 1000, TimeUnit.MILLISECONDS);
}
private void shutdownThreadPools() {
// For each threadpool create a completable future which attempts to shut it down
final var threadpoolStopTasks = threadPools.stream()
.map(tp -> CompletableFuture.runAsync(() -> {
try {
tp.shutdown();
// Await termination, force if taking too long
if (!tp.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
tp.shutdownNow();
}
} catch (InterruptedException e) {
tp.shutdownNow();
Thread.currentThread().interrupt();
}
}))
.collect(Collectors.toList());
// Create a completable future from all of the above stop tasks, wait for it to complete then
// stop the executor this tracker is running in
CompletableFuture.allOf(threadpoolStopTasks.toArray(new CompletableFuture[0]))
.thenApply((v) -> {
tracker.shutdownNow();
return null;
})
.join();
}
public void submit(ExecutorService threadPool, Runnable task) {
threadPools.add(threadPool);
threadPool.submit(() -> {
try {
task.run();
} catch (Exception e) {
// do stuff
threadpoolException.set(true);
}
});
}
public void shutdown() throws InterruptedException {
shutdownThreadPools();
tracker.shutdown();
if (!tracker.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
tracker.shutdownNow();
}
}
}
Then in your program
final var threadpoolService = new ThreadpoolService();
// Then wherever you use a threadpool delegate to the above for task submissing
final var tp1 = Executors.newFixedThreadPool(5);
threadpoolService.submit(tp1, () -> {
// some task which may fail exceptionally
return;
});
When your program needs to shutdown for some other reason
threadpoolService.shutdown();
}
Of note is that an exception triggerring the shutdown of these threadpools is not recoverable i.e. the threadpools and ThreadpoolService are no longer in a functional state after shutdown and really, this should trigger the end of the program - you could enhance this to register a shutdown hook which ends the program.
It should also be noted that I've made a lot of assumptions inc.
use of the default fork-join pool for CompletableFutures (you can just pass your own executor service)
expectation the CompletableFuture.allOf will finish in a timely manner (you can add a timeout)
hardcoded time intervals (you can make these configurable)
It also doesn't cover the below, both of which can be resolved by using a guard (maybe threadpoolException) on appropriate methods and returning some value or throwing an exception as appropriate
race conditions on the various methods (e.g. calling shutdown while a shutdown is in progress)
calling submit following a shutdown
final ExecutorService executor = Executors.newFixedThreadPool(1);
final Future<?> future = executor.submit(myRunnable);
executor.shutdown();
if(executor.awaitTermination(10, TimeUnit.SECONDS)) {
System.out.println("task completed");
}else{
System.out.println("Executor is shutdown now");
}
//MyRunnable method is defined as task which I want to execute in a different thread.
Here is run method of executor class:
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
Here it is waiting for 20 second but when i run the code it throws an exception:
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
I am not able to close the concurrent thread ruining in Java Executor class. Here is my Code flow:
Created a new Thread with Java executor class to run some task i.e written in MyRunnable
executor wait for 10 second to complete the tasks.
If the task has completed then runnable thread also got terminated.
If the task is not completed within 10 second then executor class should terminate the thread.
Everything works fine except the termination of tasks in the last scenario. How should I do it?
The shutDown() method simply prevents additional tasks from being scheduled. Instead, you could call shutDownNow() and check for thread interruption in your Runnable.
// in your Runnable...
if (Thread.interrupted()) {
// Executor has probably asked us to stop
}
An example, based on your code, might be:
final ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(new Runnable() {
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
System.out.println("Interrupted, so exiting.");
}
}
});
if (executor.awaitTermination(10, TimeUnit.SECONDS)) {
System.out.println("task completed");
} else {
System.out.println("Forcing shutdown...");
executor.shutdownNow();
}
It is generally a bad idea to terminate a running thread from the outside, because you don't know the state the thread is currently in. It's possible that it needs to do some cleanups, and it won't be able to do that when you forcefully shut it down. That's why all methods of Thread which do that are marked as deprecated.
It's much better to use one of the many techniques which are available for interprocess communication to signal the procedure running in the thread itself that it has to abort its work and exit normally. One way to do this is to add an abort() method to your runnable, which raises a flag declared as volatile. The inner loop of your Runnable checks that flag and exits (in a controlled fashion) when that flag is raised.
According to book Java Concurrency in Practice at Listing 12.3 we could test a concurrent code using the following sample code:
void testTakeBlocksWhenEmpty() {
final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
Thread taker = new Thread() {
public void run() {
try {
int unused = bb.take();
fail(); // if we get here, it’s an error
} catch (InterruptedException success) { }
}
};
try {
taker.start();
Thread.sleep(LOCKUP_DETECT_TIMEOUT);
taker.interrupt();
taker.join(LOCKUP_DETECT_TIMEOUT);
assertFalse(taker.isAlive());
} catch (Exception unexpected) {
fail();
}
}
Let's say that the following steps are executed:
taker thread started.
bb.take() returned successfully and we are just a little bit before the fail() method run.
It is called the interrupt() method.
We are at the catch block of the taker thread.
So, we are at the catch block at the moment but actually the test method failed. It is failed and we are never informed.
Is this right? If yes how could we fix this?
take is supposed to block on an empty queue. So the expected sequence of events is:
taker.start(); => start the thread
Thread.sleep(LOCKUP_DETECT_TIMEOUT); wait to make sure the thread is started and take has been called. The actual value of the constant is hard to estimate, but anything above a few hundreds of millis should be enough - alternatively you could use a CountDownLatch to know when the taker thread is started
in taker thread: bb.take(); => is supposed to block - if it doesn't fail() is called and the test fails
in main thread: taker.interrupt(); => the take() method is supposed to exit with InterruptedException
in main thread: taker.join(); => wait for some time to allow the taker thread to finish
in main thread: assertFalse(taker.isAlive()); => confirm that the taker thread has exited and is not blocked in the take method any more
Version with a latch (it assumes that if the thread is interrupted before take is called, take will exit with an InterruptedException - if not then you have no other way but to add some random sleep before calling started.await()):
void testTakeBlocksWhenEmpty() {
final CountDownLatch started = new CountDownLatch(1);
final CountDownLatch ended = new CountDownLatch(1);
final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
Thread taker = new Thread() {
public void run() {
try {
started.countDown();
int unused = bb.take();
fail(); // if we get here, it’s an error
} catch (InterruptedException success) { }
ended.countDown();
}
};
try {
taker.start();
started.await();
taker.interrupt();
assertTrue(ended.await());
} catch (Exception unexpected) {
fail();
}
}
You should add a timeout to your test method or to the latch (long enough to not interfere if the test passes, for example 5 seconds). That will avoid blocking your whole test suite.
final ExecutorService executor = Executors.newFixedThreadPool(1);
final Future<?> future = executor.submit(myRunnable);
executor.shutdown();
if(executor.awaitTermination(10, TimeUnit.SECONDS)) {
System.out.println("task completed");
}else{
System.out.println("Executor is shutdown now");
}
//MyRunnable method is defined as task which I want to execute in a different thread.
Here is run method of executor class:
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
Here it is waiting for 20 second but when i run the code it throws an exception:
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
I am not able to close the concurrent thread ruining in Java Executor class. Here is my Code flow:
Created a new Thread with Java executor class to run some task i.e written in MyRunnable
executor wait for 10 second to complete the tasks.
If the task has completed then runnable thread also got terminated.
If the task is not completed within 10 second then executor class should terminate the thread.
Everything works fine except the termination of tasks in the last scenario. How should I do it?
The shutDown() method simply prevents additional tasks from being scheduled. Instead, you could call shutDownNow() and check for thread interruption in your Runnable.
// in your Runnable...
if (Thread.interrupted()) {
// Executor has probably asked us to stop
}
An example, based on your code, might be:
final ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(new Runnable() {
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
System.out.println("Interrupted, so exiting.");
}
}
});
if (executor.awaitTermination(10, TimeUnit.SECONDS)) {
System.out.println("task completed");
} else {
System.out.println("Forcing shutdown...");
executor.shutdownNow();
}
It is generally a bad idea to terminate a running thread from the outside, because you don't know the state the thread is currently in. It's possible that it needs to do some cleanups, and it won't be able to do that when you forcefully shut it down. That's why all methods of Thread which do that are marked as deprecated.
It's much better to use one of the many techniques which are available for interprocess communication to signal the procedure running in the thread itself that it has to abort its work and exit normally. One way to do this is to add an abort() method to your runnable, which raises a flag declared as volatile. The inner loop of your Runnable checks that flag and exits (in a controlled fashion) when that flag is raised.
I have the following piece of code:
public class Test {
List<Future> future = new ArrayList<Future>();
public static void main(String args[]) throws Exception {
Adapter b1 = new Adapter();
final ExecutorService threadPool = Executors.newCachedThreadPool();
for(//iterate for number of files) {
while(data exists in file) {
//Call a function to process and update values in db
future.add(threadPool.submit(new Xyz(b1)));
//read next set of data in file;
}
}
try {
for(Future f: future) {
f.get();
}
}
catch(Exception e) {
throw e;
}
}
}
class Xyz implements Runnable {
private Adapter a1;
public Xyz(Adapter al) {
this.a1=a1;
}
#Override
public void run() {
try {
a1.abc();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
When the number of files is 1 (for loop runs for 1 time), the code runs fine.
But, when the number of files increases, the code never returns back from future.get() method.
just out of curiosity.. do i need to shutdown the executor somewhere ??
Yes, and this is likely the problem. Each Future.get() will block until the corresponding task is complete, then once all the tasks are complete your main thread will exit. But your java process will not exit because the thread pool threads are still active in the background. You should shut down the executor once you have finished with it, most likely as the last thing in your main method.
I also note that you're submitting many tasks that wrap the same Adapter instance and all call its abc() method - check that there's nothing in there that will deadlock when called simultaneously in more than one thread.
Your Callable::call / Runable::run does not return. Otherwise the corresponding future would not block.
Additional executor.shutdown or future.cancel will thow an InterruptedException to stop the thread processing the object you submitted but it is up to you if to catch it or not. Your are responsible for making the jobs you submitted stop.
When you submit thousands Callables/Runnables to a CachedExecutor that it might spawn so many threads that your machine gets so slow that you think it takes forever. But you would have noticed that.
When dealing with an undefined number of parallelizable tasks i suggest to use a FixedThreadPool with not much more threads that there are cpu cores.
Edit: Therefore when you set a breakpoints at a1.abc(); and step forward you will probably find out that it never returns.