Make other threads wait until ScheduledExecutorService completes all tasks - java

The main goal is to run a method using ScheduledExecutorService and wait until all its tasks complete before resuming the main thread.
I've created a utility method in custom Scheduler class that accepts any Runnable:
public void scheduleFunction(Runnable function) {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> producerHandle = scheduler.scheduleAtFixedRate(function, initialDelay, interval, MILLISECONDS);
scheduler.schedule(() -> { producerHandle.cancel(true); }, timeout, MILLISECONDS);
}
And use it like this in other class when I need execute its method in scheduled mode:
public void sendToKafka() {
Scheduler.scheduleFunction(this::produce);
}
This work fine, except one thing.
When the main thread reaches sendToKafka() it calls Scheduler to schedule a function. Dut the main thread keeps running, at the same time the Scheduled function starts to work.
Actual result:
two threads running at the same time
Expected result:
when scheduler thread starts the main thread stops and waits until scheduler completes execution
How can I achieve this?

Since you are creating and abandoning a ScheduledExecutorService in this method, you should call shutdown() to support timely release of the resources. If you do that, you can call awaitTermination to wait for the completion of all pending jobs.
public void scheduleFunction(Runnable function) {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> producerHandle
= scheduler.scheduleAtFixedRate(function, initialDelay, interval, MILLISECONDS);
scheduler.schedule(() -> {
producerHandle.cancel(true);
scheduler.shutdown();
}, timeout, MILLISECONDS);
try {
scheduler.awaitTermination(Long.MAX_VALUE, MILLISECONDS);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
Note that when you don’t need interruption, you can simply use
public void scheduleFunction(Runnable function) {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(function, initialDelay, interval, MILLISECONDS);
scheduler.schedule(() -> scheduler.shutdown(), timeout, MILLISECONDS);
try {
scheduler.awaitTermination(Long.MAX_VALUE, MILLISECONDS);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
as shutting down the ScheduledExecutorService implies stopping to reschedule the job; only if there’s an ongoing execution it will be completed and awaitTermination will wait for it.

Related

How to end a thread in executor service if thread takes too long?

Sample executor service
static class MyRunnable implements Runnable {
private String serverName;
public MyRunnable(String serverName) {
super();
this.serverName = serverName;
}
#Override
public void run() {
...
conn = new ch.ethz.ssh2.Connection(serverName);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user, pass);
logger.info("Connecting to " + server);
if (isAuthenticated == false) {
logger.info(server + " Please check credentials");
}
sess = conn.openSession();
...
}
}
public static void main(String[] args) {
List<String> serverList = ...;
ExecutorService executor = Executors.newFixedThreadPool(20);
for (String serverName : serverList) {
MyRunnable r = new MyRunnable(serverName);
executor.execute(r);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);
}
Right here is a sample code of my executor service. But with this logic when I meet a server that fails to connect or takes too long to connect it creates a a hang time within my application. I want to end/kill the thread if it takes longer than x amount of time to connect. How can I terminate the thread task if it does not connect to server within 2 seconds.
Attempt
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, 25, 500, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1));
I added the following code but apparently it does not end the thread if it takes longer than 2000 milliseconds.
Attempt 2
Future<?> future = executor.submit( new task));
try {
future.get(2000, TimeUnit.MILLISECONDS); // This waits timeout seconds; returns null
}
catch(TimeoutException e) {
future.cancel(true);
// System.out.println(server + "name");
}
How can I terminate the thread task if it does not connect to server within 2 seconds.
This is difficult thing to do typically because even if you interrupt the thread (like the other answers mention) there's no guarantee that the thread will stop. Interrupt just sets a flag on the thread and it's up to the code to detect the status and stop. This means that a ton of threads may be in the background waiting for the connects.
In your case however you are using the ch.ethz.ssh2.Connection.connect() method. Turns out there is a connect method that takes a timeout. I think you want the following:
// try to connect for 2 seconds
conn.connect(null, 2000, 0);
To quote from the connect method javadocs:
In case of a timeout (either connectTimeout or kexTimeout) a SocketTimeoutException is thrown.
You have to do awaitTermination() first, then check the return value, and then do shutdownNow(). shutdown() does not guarantee instant stoppage of the service, it just stops taking new jobs, and waits for all jobs to complete in order. shutdownNow() on the other hand, stops taking new jobs, actively attempts to stop all running tasks, and does not start any new one, returning a list of all waiting-to-execute jobs.
From JavaDocs :
The following method shuts down an ExecutorService in two phases,
first by calling shutdown to reject incoming tasks, and then calling
shutdownNow, if necessary, to cancel any lingering tasks:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
You can always call future.get(timeout...)
It will return timeout exception if it did not finish yet... then you can call future.cancel().
As long as you deal with threads in Java the only safe way to stop the thread is to interrupt it. You can call shutdown() first and then wait. This method doesn't interrupt threads.
If it doesn't help then you call shutdownNow() which tries to cancel tasks by setting interrupted flag of each thread to true. In that case if threads are blocked/waiting then InterruptedException will be thrown. If you check interrupted flag somewhere inside your tasks then you are good too.
But if you have no other choice but to stop threads you still can do it. One possible solution of getting access to workers is to trace all created threads inside ThreadPoolExecutor with help of custom thread factory.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestThreadPoolEx {
static class CustomThreadFactory implements ThreadFactory {
private List<Thread> threads = new ArrayList<>();
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
threads.add(t);
return t;
}
public List<Thread> getThreads() {
return threads;
}
public void stopThreads() {
for(Thread t : threads) {
if(t.isAlive()) {
try {
t.stop();
} catch (Exception e) {
//NOP
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
CustomThreadFactory factory = new CustomThreadFactory();
ExecutorService ex = Executors.newFixedThreadPool(1, factory);
ex.submit(() -> {
while(true);
});
ex.shutdown();
ex.awaitTermination(5, TimeUnit.SECONDS);
ex.shutdownNow();
ex.awaitTermination(5, TimeUnit.SECONDS);
factory.stopThreads();
}
}
This is sure unsafe but should fit your requirements. In this case it's able to stop while(true) loop. Cancelling tasks won't be able to do that.

ScheduledFuture.get() is still blocked after Executor shutdown

I want to run some periodic task in background and I want to do it right.
So I schedule my task with ScheduledExecutorService.scheduleWithFixedDelay(..) and call ScheduledFuture.get() on the separate thread to control the life of the task, catch uncaught exceptions from it and get notified if the task is cancelled.
The problem is that if ScheduledExecutorService.shutdown() is called while the task is executing, than ScheduledFuture does not get notified and its get() method stays blocked forever.
And here comes the simple code to illustrate the problem:
public final class SomeService {
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private final SomePeriodicTask task = new SomePeriodicTask();
private ScheduledFuture<?> future;
public void start() {
future = executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS);
final Runnable watchdog = new Runnable() {
#Override
public void run() {
try {
future.get();
} catch (CancellationException ex) {
System.out.println("I am cancelled");
} catch (InterruptedException e) {
System.out.println("I am interrupted");
} catch (ExecutionException e) {
System.out.println("I have an exception");
}
System.out.println("Watchdog thread is exiting");
}
};
new Thread(watchdog).start();
}
public void shutdownAndWait() {
System.out.println("Shutdown requested");
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) { //BTW When and why could this happen?
System.out.println("Waiting for shutdown was interrupted");
}
System.out.println("Executor is shutdown " + executor.isShutdown());
}
}
First, simple task which returns quickly
final class SomePeriodicTask implements Runnable {
#Override
public void run() {
System.out.print("I am just doing my job...");
System.out.println("done");
}
}
If we run it like this
public static void main(String[] args) throws InterruptedException {
SomeService service = new SomeService();
service.start();
Thread.sleep(3000);
service.shutdownAndWait();
System.out.println("Future is cancelled " + service.future.isCancelled());
System.out.println("Future is done " + service.future.isDone());
}
then the output is
I am just doing my job...done
I am just doing my job...done
I am just doing my job...done
Shutdown requested
I am cancelled
Watchdog thread is exiting
Executor is shutdown true
Future is cancelled true
Future is done true
totally as expected.
But if we modify the task to simulate some heavy job
final class SomePeriodicTask implements Runnable{
#Override
public void run() {
System.out.print("I am just doing my job...");
try {
Thread.sleep(1500); //Heavy job. You can change it to 5000 to be sure
} catch (InterruptedException e) {
System.out.println("Task was interrupted");
}
System.out.println("done");
}
}
so that the call to shutdown() happens while the task is executing... then the output is
I am just doing my job...done
I am just doing my job...Shutdown requested
done
Executor is shutdown true
Future is cancelled false
Future is done false
So what happened here... Executor is shutting down, as expected. It lets the current task to finish its job, as expected. We see that executor did finish shutting down, but our ScheduledFuture did not get cancelled and its get() method is still blocked and the watchdog thread prevents JVM from exiting and hangs forever.
Of course there are workarounds. For example I can call future.cancel(false) manually before shutdown or make watchdog a daemon thread or even try to schedule shutdown of Executor by himself so that it does not overlap with running task... But all of above have drawbacks and when code will get more complicated things can go sideways.
And anyway, I am seeking for your expert opinion because I will have no peace until I understand why it doesn't behave like it should. If it is a bug in jdk it must be reported. If I misunderstand something and my code is wrong, I must know it...
Thanks in advance
The first thing to understand is that for a periodic task, a normal completion does not turn the state of the Future to done as it expects to be rescheduled and possibly rerun.
This interferes with the semantics of Executor.shutdown; it will cancel all pending tasks but let the currently running tasks complete. So your currently running task completes normally and doesn’t set its state to done as it never does, but isn’t rescheduled because the executor has been shut down.
Even if you use shutdownNow it will interrupt the currently running tasks but not cancel them and since your task catches the InterruptedException and completes earlier but normally, there will be no state transition to done.
The best place to add the desired behavior of cancelling even tasks that completed normally upon shutdown is the Executor implementation; just change the line
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
to
private final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1) {
#Override
protected void afterExecute(Runnable r, Throwable t) {
if(t==null && isShutdown() && r instanceof RunnableScheduledFuture<?>)
{
RunnableScheduledFuture<?> rsf = (RunnableScheduledFuture<?>)r;
if(rsf.isPeriodic()) rsf.cancel(false);
}
};
};

java executor delay not working

Ok so I have tried 3 different options of delayed executors for a void/runnable/timertask that I want to run after 5 seconds but all the codes I used didn't work. They would immediatly run the code.
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(clearstage(), 10, 10, SECONDS);
executor.shutdown();
the second code I tried:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(clearstage(), 0, 5, TimeUnit.SECONDS);
executor.shutdown();
and with those I used a runnable task like this: public Runnable clearstage(){//code}
I have also tried the timertask:
reviveplayerover = clearstage();
Timer timer = new Timer();
timer.scheduleAtFixedRate(reviveplayerover, 5000);
reviveplayer(namee, name);
timer.cancel();
and then used the: public TimerTask clearstage(){//code}
You need to make sure your 'main()' method does not exit before the scheduled task have executed.
// Example with a one-shot delay
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(clearstage(), 5, TimeUnit.SECONDS);
executor.shutdown();
executor.awaitTermination(6, TimeUnit.SECONDS);
System.out.println("Done.");
// And your clearstage() must be implemented like this:
private static Runnable clearstage() {
return new Runnable() {
#Override
public void run() {
// Code goes here...
}
};
}
In your second example using ScheduledExecutorService
executor.scheduleWithFixedDelay(clearstage(), 0, 5, TimeUnit.SECONDS);
The second argument is initialDelay. Here is the Javadoc
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit)
...
initialDelay - the time to delay first execution
You are passing in 0 so the first scheduled Runnable will not delay. ExecutorService.shutdown() runs all tasks that were scheduled and then shuts down. Since you are also calling shutdown() immediately after, the task will not be scheduled and will not execute.
Another option if using ScheduledExecutorService is to schedule a task with a delay using the public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); method. Since it is scheduled before calling shutdown(), it will always finish.
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
scheduledFuture = executor.schedule(clearstage(), 5, TimeUnit.SECONDS);
executor.shutdown();
You can also wait for your scheduled future to be complete. It is unclear from the question exeactly what you are looking for.
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> scheduledFuture = executor.schedule(clearstage(), 5, TimeUnit.SECONDS);
scheduledFuture.get(); // Wait for completion
executor.shutdown()

ScheduledExecutorService - program not ending after one-shot action

I have a scheduled task in my program that closes a frame after a given period of time. However, after the task has been executed, the program keeps running as if the ScheduledExecutorService was still running on a different thread.
This is the relevant part of my code:
int delay = 1000;
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.schedule(() -> {
System.out.println("executed");
getWindow().closeWindow();
// ex.shutdown();
}, delay, TimeUnit.MILLISECONDS);
Here the task is executed after a 1 second delay, "executed" is printed once, the frame closes, and the program keeps running even after this code. If I uncomment the ex.shutdownNow();, the program successfully ends as intended. However, I cannot figure out why this is happening. I also failed to find anything from the rest of the Internet.
MCVE:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
int delay = 1000;
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.schedule(() -> {
System.out.println("executed");
// ex.shutdown();
}, delay, TimeUnit.MILLISECONDS);
}
}
The lambdas might've given it away, but this is indeed Java 8.
Why is the program not stopping after the task has been executed?
The ScheduledExecutorService thread pool returned by Executors#newSingleThreadScheduledExecutor() uses non daemon threads. Until you shut down the thread pool, these are still alive awaiting tasks. A JVM does not end while non-daemon threads are alive.
You can use the overloaded Executors#newSingleThreadScheduledExecutor(ThreadFactory) and provide your own ThreadFactory implementation which creates daemon threads. Note that this risks the case where your task may not even run because the JVM would exit before the task's scheduled time.
Do as you've discovered and shut it down. Note that you should shut always it down somewhere safe, where the operation can't fail.
The Java Virtual Machine runs until all threads that are not daemon threads have died. And Executors.defaultThreadFactory() creates each new thread as a non-daemon thread. However, there is an overload of Executors.newSingleThreadScheduledExecutor(); which takes a ThreadFactory as a parameter, if you care to venture in that direction.
public static void main(String[] args) {
int delay = 1000;
class DaemonFactory implements ThreadFactory
{
#Override
public Thread newThread(Runnable r)
{
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
ThreadFactory tf = new DaemonFactory();
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor(tf);
ex.schedule(() -> {
System.out.println("executed");
}, delay, TimeUnit.MILLISECONDS);
}
I would approach this entirely differently. You state:
I have a scheduled task in my program that closes a frame after a given period of time.
Why not instead use a Swing Timer for this as this was built to work well with the Swing event thread?
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
((Timer) e.getSource()).stop();
someWindow.dispose();
}
}).start();
You can call shutdown from ScheduledExecutorService as it will wait for thread execution and then finalize thread pool. As you can see in Javadoc: "Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will
be accepted. Invocation has no additional effect if already shut down."
Example:
...
scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS);
scheduledExecutorService.shutdown();
...
I am starting scheduler from onCreate() and stopping it in onDestroy() approach to stop the scheduler service.
public MyActivity extends Activity
{
ScheduledExecutorService scheduledExecutorService;
ScheduledFuture<?> scheduledFuture;
private int apiThreshold = 10;//seconds
onCreate()
{
startScheduler();
}
onDestroy()
{
if (scheduledFuture != null)
{
stopScheduler();
}
shutDownService();
super.onDestroy();
}
public void startScheduler() {
Debug.e(TAG, "inside start scheduler");
scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// call method to do your task/perform your repeated task
}
}, 4, apiThreshold, TimeUnit.SECONDS);
}
public void shutDownService()
{
if (scheduledExecutorService != null) {
Log.e(“test,"in shutDown service close if not null");
scheduledExecutorService.shutdownNow(); // shutdown will allow the final iteration to finish
// executing where shutdownNow() will kill it immediately
Log.e(“test,"is service shutdown(true/false)=="+scheduledExecutorService.isShutdown());
}
}
}

How can I replace Thread.sleep() in an infinite loop?

I have an infinite loop inside my main, it runs a job which is also an infinite loop, and wait for it to throw an error. Then it sleeps for a given amount of time and starts the task again.
public static void main(String[] args) {
while (true) {
try {
MyClass myClass = new MyClass();
myClass.startInfiniteLoop();
}
catch (SomeException ex) {
try {
Thread.sleep(MyClass.DEFAULT_SLEEP_TIME);
}
catch (InterruptedException ex2) {
System.exit(-1);
}
}
}
}
This works fine, but I wonder if this could be done better, perhaps with an ExecutorService as I (and my IDE) don't like Thread.sleep() in a while (true) loop.
I have read a lot of questions and their answers about ScheduledExecutorService and task management, but I did not find this particular case since it's not really a schedule, I don't know if and when the task if going to end.
You can use a ScheduledExecutorService:
ScheduledExecutorService s=Executors.newScheduledThreadPool(1);
s.scheduleWithFixedDelay(new Runnable() {
public void run() {
try {
MyClass myClass = new MyClass();
myClass.startInfiniteLoop();
} catch(SomeException ex) {}
}
}, 0, MyClass.DEFAULT_SLEEP_TIME, TimeUnit.MILLISECONDS);
The key point is to use scheduleWithFixedDelay rather than scheduleAtFixedRate to ensure the specified time elapses between the subsequent executions just like with your sleep approach. However, note that even with “fixed rate” the new execution will not start when the old one has not finished yet. It’s documentation says: “If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.”
Further note that you still have to catch the exception like in my code example as otherwise the executor will cancel the scheduled task once it threw an uncatched exception.
If you can take the MyClass and rework it to have a Runnable that does what only one loop iteration of the MyClass would have done, then you can use a scheduling executor service, telling the service to run the Runnable once every time period.
--- Updated by request of a quick example ---
The following is not strictly correct Java code, it is pesudo-java.
public class MyRepeatingTask implements Runnable {
private final ScheduledThreadpoolExecutor executor;
public MyRepeatingTask(ScheduledThreadpoolExecutor executor) {
this.executor = executor;
}
public void run() {
try {
doMyVariableLengthThing();
// alternatively, you could also schedule a new instance
executor.schedule(this, 1, TimeUnit.SECONDS);
} catch (Exception e) {
cleanup();
}
}
}
and then to start the ball rolling
ScheduledThreadpoolExecutor executor = new ScheduledThreadpoolExecutor(1);
executor.execute(new MyRepeatingTask(executor));

Categories

Resources