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()
Related
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.
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());
}
}
}
I am using Executors.newFixedThreadPool to start a thread every two minutes and the thread sends data to server.
After sometime there will not be any data to be sent. In this case how do I shutdown the pool.
Can I initiate the shutdown of the pool from the same thread which is run through ThreadPool
Code is :
scheduledThreadPool = Executors.newScheduledThreadPool(5);
Runnable runnable = new Runnable() {
#SuppressLint("ShowToast")
public void run() {
Log.e("Thread Pool -1 is running", "ThreadPool-1");
sendDataToServer();
}
};
scheduledThreadPool.scheduleWithFixedDelay(runnable, INITIAL_DELAY,
DELAY, TimeUnit.SECONDS);
}
Keep your scheduled future for future reference.
final ScheduledFuture<?> scheduledFuture = scheduledThreadPool.scheduleWithFixedDelay(runnable, INITIAL_DELAY,
DELAY, TimeUnit.SECONDS);
To cancel, invoke cancel(boolean) method on your Future:
scheduledFuture.cancel(true);
You will have to keep all the Futures you will create from the pool to be able to cancel later.
I'm using Spring's TaskScheduler to schedule a periodic task.
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
I understand that I can call cancel() on the ScheduledFuture to stop the recurring task from being executed. But I'd like to cancel the recurring scheduled task depending on the result of the execution of the task, and am not sure how to best do that.
Does the ScheduledFuture give me access to the result of EACH executed task? Or do I need some sort of task listener that can keep a reference to this ScheduledFuture, and cancel it that way? Or something else?
Ok it looks like it is possible, but there is probably a better approach.
Since a recurring job only takes a Runnable (with a void return type) there is no way to return the result of the task. So the only way to stop the recurring task is to make the task perform a side-effect, e.g. adding a stop message to a queue. Then a separate thread would need to monitor this queue, and it could cancel the job once it sees the message.
Very messy and complicated.
A better alternative is to create a normal (one time) scheduled task. The task itself can then decide whether or not it needs to schedule another task, and can do the scheduling of the next task itself.
Keep a handle or the original fixed rate ScheduledFuture, then when the condition arises where you want to cancel it, schedule a new task that does the cancel.
You might also be able to do something with a RunnableScheduledFuture.
From the ScheduledExecutorService docs
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html
import static java.util.concurrent.TimeUnit.*;
class BeeperControl {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
final Runnable beeper = new Runnable() {
public void run() { System.out.println("beep"); }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
scheduler.schedule(new Runnable() {
public void run() { beeperHandle.cancel(true); }
}, 60 * 60, SECONDS);
}
}
Here is a modified beeper example that demonstrates how to make a decision after EACH scheduled task. I used a latch so I could wrap it in a test case and assert the right thing happened (and of course to keep the test runner's thread from stopping). I also changed the intervals (it beeps every 10ms after an initial 10ms delay) so the test could be copied, pasted, and executed in a second as opposed to an hour.
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class BeeperTest {
class BeeperControl {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, (runnable) -> {
Thread thread = new Thread(runnable);
thread.setName("MyAwesomeBeeperTestThread");
thread.setDaemon(true);
return thread;
});
public void beepTheNumberOfTimesIWant(CountDownLatch latch) {
long initialDelay = 10;
long frequency = 10;
TimeUnit unit = TimeUnit.MILLISECONDS;
final int numberOfTimesToBeep = 5;
AtomicInteger numberOfTimesIveBeeped = new AtomicInteger(0);
final ScheduledFuture[] beeperHandle = new ScheduledFuture[1];
beeperHandle[0] = scheduler.scheduleAtFixedRate(() -> {
if (numberOfTimesToBeep == numberOfTimesIveBeeped.get()) {
System.out.println("Let's get this done!");
latch.countDown();
beeperHandle[0].cancel(false);
}
else {
System.out.println("beep");
numberOfTimesIveBeeped.incrementAndGet();
}
}, initialDelay, frequency, unit);
}
}
#Test
public void beepPlease() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
BeeperControl control = new BeeperControl();
control.beepTheNumberOfTimesIWant(latch);
boolean completed = latch.await(1, TimeUnit.SECONDS);
Assert.assertTrue("Beeper should be able to finish beeping" +
"within allotted await time.", completed);
}
}
I am following up an interesting question on so, on usage of ScheduledThreadPoolExecutor for some repeating task.
Scheduling this object returns a ScheduledFuture object which one can use to cancel the next run of the task.
One thing to note here is the task itself is completely decoupled from the schedule--
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
ScheduledFuture nextSchedule =
executor.schedule(task, 60000, TimeUnit.MILLISECONDS);
where-
SomeTask task = new SomeTask();
So the task itself is not aware of the schedule. Please enlighten if there is a way to get the task to cancel and create a new schedule for itself.
Thanks
There's no reason why the task cannot reference the ScheduledExecutorService and schedule itself to run again if required:
// (Need to make variable final *if* it is a local (method) variable.)
final ScheduledExecutorService execService = Executors.newSingleThreadScheduledExecutor();
// Create re-usable Callable. In cases where the Callable has state
// we may need to create a new instance each time depending on requirements.
Callable<Void> task = new Callable() {
public Void call() {
try {
doSomeProcessing();
} finally {
// Schedule same task to run again (even if processing fails).
execService.schedule(this, 1, TimeUnit.SECONDS);
}
}
}
Pass the executor to the task, so that it can make manipulations with it:
SomeTask task = new SomeTask(executor);