We need to implement a feature that allows us to cancel a future job. Given that this job is doing DB calls and we need to rollback\cleanup any updates made before cancel was fired.
This is what I have tried, but "Thread.currentThread().isInterrupted()" always return false:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
final Future future = executor.submit(new Callable() {
#Override
public Boolean call() throws Exception {
// Do Some DB calls
if (Thread.currentThread().isInterrupted()) {
// Will need to roll back
throw new InterruptedException();
}
return true;
}
});
executor.schedule(new Runnable() {
public void run() {
future.cancel(true);
}
}, 1, TimeUnit.SECONDS);
Is this the right approach to achieve our target? And how to know if the job was cancelled in order to cancel\roll back changes?
I believe that you complete the database calls before the second task gets a chance to run. When you have only a single executor it is possible that it does not schedule time for the second scheduled task before the first completes. This following snippet does get interrupted:
import java.util.*;
import java.util.concurrent.*;
public class Main {
public static void main(String[] arg) {
ScheduledExecutorService runner = Executors.newScheduledThreadPool(2);
// If this is 1 then this will never be interrupted.
final Future f = runner.submit(new Callable<Boolean>() {
public Boolean call() throws Exception {
System.out.println("Calling");
while (! Thread.currentThread().isInterrupted()) {
;
}
System.out.println("Interrupted");
return true;
}
});
runner.schedule(new Runnable() {
public void run() {
System.out.println("Interrupting");
f.cancel(true);
}
}, 1, TimeUnit.SECONDS);
}
}
First it seems the thread pool is not creating new thread for you so your cancel task will get called only after the DB task finishes. So I changed the pool size in yours example to 2 and it worked.
Related
I have a simple java program I use to generate elements and insert them in DB every X seconds during a specific time.
The generation is done with a scheduleAtFixedRate. there is only one of these.
I want my program to quit completely when the scheduled task is over. To do so, I use System.exit() when the task is canceled, but is it the correct way to do this ?
Here is my current code:
public static void main(String[] args) throws InterruptedException {
c = generateDbConnection(url, user, password);
if (c != null) {
s = generateDbStatement(c);
} else {
System.out.println("ERROR");
return;
}
initialTimestamp = new Date();
TimeUnit.SECONDS.sleep(1);
generateForAnHour();
}
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* Generator thread handler Uses Statement from main function
*/
public static void generateForAnHour() {
final Runnable runner = new Runnable() {
public void run() {
String[][] data = new String[numberOfIds][2];
for (int i = 0; i < numberOfIds; i++) {
data[i] = generateDevice();
insertDevice(s, data[i][0], data[i][1]);
}
quantityOfIds += numberOfIds;
}
};
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 5, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
public void run() {
generatorHandle.cancel(true);
System.out.println("Scheduled ID generator terminated.");
System.exit(0); //TODO Is it really correct way to do it
}
}, timeToRun, TimeUnit.SECONDS);
}
I am not sure if this is the correct way to stop the execution of your program if it has some more functions, but I, personally, find it an OK way. :D
So, as it turned out, ScheduledExecutorService seemingly creates non-daemon threads with its default ThreadFactory, perhaps we need to supply a daemonic one to it.
However, if we are to call ExecutorService#shutdown or the forceful ExecutorService#shutdownNow, it will stop both tasks from executing, thus removing the thread(s) that prevent the application from ending its job:
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static void main(String[] args) {
// Some service code here
generateForAnHour();
}
public static void generateForAnHour() {
// Some code that does work
final Runnable runner = () -> System.out.println("Running...");
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 1, TimeUnit.SECONDS);
// Code that interrupts the worker after a specified time
scheduler.schedule(scheduler::shutdown, 5, TimeUnit.SECONDS);
}
Output:
Running...
Running...
Running...
Running...
Running...
Running...
Process finished with exit code 0
I hope this will help. :D
This answer is secondary to this one, but it has a different way to solve the problem, so I thought it is appropriate enough to create a separate answer.
If you want to have some more tasks in the future, I believe this solution is more scalable and is more "correct thing".
It creates daemon threads for both runner and interrupter. I think it would be better to create a normal thread factory for the interrupter, but I failed to make it working, so it's better to stick to my first answer...
Here generateForAnHour returns a Future that is used to wait for the time needed.
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1 , new ThreadFactory() {
#Override
public Thread newThread(final Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
});
public static void main(String[] args) throws InterruptedException, ExecutionException {
// Some service code here
generateForAnHour().get();
}
public static ScheduledFuture<Boolean> generateForAnHour() {
// Some code that does work
final Runnable runner = () -> System.out.println("Running...");
final ScheduledFuture<?> generatorHandle = scheduler.scheduleAtFixedRate(runner, 0, 1, TimeUnit.SECONDS);
// Code that interrupts the worker after a specified time
return scheduler.schedule(() -> generatorHandle.cancel(false), 5, TimeUnit.SECONDS);
}
If you won't call Future#get, you'll receive only one Running... in best case or none at all.
If you decide to return the runner future, you'll probably get nasty CancellationException in the get() call:
Exception in thread "main" java.util.concurrent.CancellationException
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:121)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at com.xobotun.Test.main(Test.java:30)
I'd use the ExecutorService::shutdown approach as the stabler and more understandable one. :D
I need a thread that will only run once at a time, for example if it's called for the first time it will run, if it is called a second time, the first should stop completely and be allowed to die and a new one should take it's place.
I was ran a small test to see what was actually happening between each execution, the results show that the thread doesnt die but instead two threads are being executed alongside:
public class Test {
Worker worker = new Worker();
#Override
public void valid() {
try {
if (worker.running) {
worker.running = false;
worker.join();
}
} catch (InterruptedException iex) {
worker.running = false;
}
worker = new Worker();
worker.start();
}
private final class Worker extends Thread {
private volatile boolean running = true;
#Override
public void run() {
while (running) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
}
}
}
}
}
The results are as follows:
//Upon first execution
Thread-4
Thread-4
Thread-4
Thread-4
//When I execute it again
Thread-7
Thread-4
Thread-7
Thread-4
Thread-7
Thread-4
I've tried using ExecutorService or using while(!Thread.currentThread.isInterrupted) instead of the boolean flag, and got the same results.
How can I properly stop "Thread-4" and have only one of them running?
The actual issue comes from a thread that will cycle through a list and update things on discord chat by request, what the thread does is listen to input and change as suggested by kidney I'm trying to use executor.submit() and Future
private ExecutorService executor = Executors.newSingleThreadExecutor();
private Future<Void> worker;
private void setupImageThread() {
if (!worker.isDone() && !worker.isCancelled()) {
worker.cancel(true);
}
this.worker = (Future<Void>)executor.submit(new Cycler(Listener.queue(), this.links, Cel.cMember()));
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
Runnable timeout = () -> {
executor.shutdown();
};
ses.schedule(timeout, 100, TimeUnit.SECONDS);
}
How can I go about initializing the Future for the first time it is created?
Using single thread executor service, I would try something like this:
public class Test {
private static ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Void> worker;
public Test() {
this.worker = executor.submit(new Worker());
}
#Override
public void valid() {
if (!worker.isDone() && !worker.isCancelled()) {
worker.cancel(true); // Depends on whether you want to interrupt or not
}
this.worker = executor.submit(new Worker());
}
}
And make Worker implement Runnable.
It seems that the method valid can be called several times simultaneously. That means, every of those calls will wait to end only for one thread (Worker), whereas, every of them creates its own Worker and you lose a pointer to it, so it impossible to stop bunch of new created workers.
You should make the valid method synchronized: synchronized void valid() it will prevent creating many workers:
#Override
synchronized public void valid() {
...
}
One more thing to say. You put the while loop outside the try-catch, which is wrong: if the tread gets interrupted, the interruption doesn't kill it, because next interation gets started, so it should be like that:
#Override
public void run() {
try {
while (running) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(2000);
}
catch (InterruptedException iex) {
//you don't need here Thread.currentThread().interrupt() call, because the thread has alredy been interrupted.
// The return statement here is also obsolete, I just use it as an example, but you can use empty braces.
return;
}
}
}
I'm using a 3rd party function (say runThird()) that has a tendency to loop indefinitely and has no timeout facility built in. However, I can kill it (killThird()). Is there a proper way to do this (i.e. some concurrency construct)?
Here's my attempt at this:
java.lang.Thread thread = new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(TIMEOUT);
} catch (java.lang.InterruptedException e){
return;
}
killThird();
}
});
thread.start();
RunThirdResult rtr = runThird();
if (thread != null){
thread.interrupt();
}
But I'm not sure I like the overhead of creating a thread, using sleep and the contrivance of interrupting the thread if runThird() returns.
Let's assume runThird() retuns Integer ...
// ... in your class ...
private ExecutorService executor = Executors.newCachedThreadPool();
//... then somewhere, where you want to call runThird()
Future<Integer> handle = executor.submit( new Callable<Integer>(){
#Override Integer call(){
return runThird(); // Assume you made it available here ...
}
}
Integer result;
try{
result = handle.get(TIMEOUT,UNIT); // TIMEOUT and UNIT declared somewhere above ...
}
catch(TimeoutException ex) {
killThird();
// HANDLE result not being set!
}
// ... use result.
I would use a ScheduledExecutorService for this. Schedule it to be killed.
volatile RunThirdResult rtr;
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.schedule(new Runnable(){
public void run(){
if(rtr == null) killThird();
}
}, TIMEOUT_IN_MILLIS, TimeUnit.MILLISECONDS);
RunThirdResult rtr = runThird();
Something like that? The most interesting part is StoppableWrapper#stop(), cause graceful cancellation is a hard thing and there's no common approach for all cases. One time you need to clear filesystem, other time to close network connection, etc. In your sample, you just call interrupt(), so I assumed runThird() honors being interrupted and will take care to clean things behind itself.
class Sample {
final ExecutorService tasksExecutor = Executors.newCachedThreadPool();
class StoppableWrapper implements Runnable {
private final Runnable task;
private final CountDownLatch executed;
StoppableWrapper(Runnable task, CountDownLatch executed) {
this.task = task;
this.executed = executed;
}
void stop() {
// e.g. Thread.currentThread().interrupt()
}
#Override
public void run() {
task.run();
executed.countDown();
}
}
public void scheduleTimingOutTaskExecution(final long timeout) {
final CountDownLatch executed = new CountDownLatch(1);
final StoppableWrapper command = new StoppableWrapper(new RunThirdInstance(), executed);
tasksExecutor.execute(command);
tasksExecutor.execute(new Runnable() {
#Override
public void run() {
try {
if (!executed.await(timeout, TimeUnit.MILLISECONDS)) {
command.stop();
// additionally, you can make stop() return boolean after time-out as well and handle failure
}
} catch (InterruptedException e) {
// handle stopper exception here
}
}
});
}
}
I'm looking to write some concurrent code which will process an event. This processing can take a long time.
Whilst that event is processing it should record incoming events and then process the last incoming events when it is free to run again. (The other events can be thrown away). This is a little bit like a FILO queue but I only need to store one element in the queue.
Ideally I would like to plug in my new Executor into my event processing architecture shown below.
public class AsyncNode<I, O> extends AbstractNode<I, O> {
private static final Logger log = LoggerFactory.getLogger(AsyncNode.class);
private Executor executor;
public AsyncNode(EventHandler<I, O> handler, Executor executor) {
super(handler);
this.executor = executor;
}
#Override
public void emit(O output) {
if (output != null) {
for (EventListener<O> node : children) {
node.handle(output);
}
}
}
#Override
public void handle(final I input) {
executor.execute(new Runnable() {
#Override
public void run() {
try{
emit(handler.process(input));
}catch (Exception e){
log.error("Exception occured whilst processing input." ,e);
throw e;
}
}
});
}
}
I wouldn't do either. I would have an AtomicReference to the event you want to process and add a task to process it in a destructive way.
final AtomicReference<Event> eventRef =
public void processEvent(Event event) {
eventRef.set(event);
executor.submit(new Runnable() {
public vodi run() {
Event e = eventRef.getAndSet(null);
if (e == null) return;
// process event
}
}
}
This will only ever process the next event when the executor is free, without customising the executor or queue (which can be used for other things)
This also scales to having keyed events i.e. you want to process the last event for a key.
I think the key to this is the "discard policy" you need to apply to your Executor. If you only want to handle the latest task then you need a queue size of one and a "discarding policy" of throw away the oldest. Here is an example of an Executor that will do this
Executor latestTaskExecutor = new ThreadPoolExecutor(1, 1, // Single threaded
30L, TimeUnit.SECONDS, // Keep alive, not really important here
new ArrayBlockingQueue<>(1), // Single element queue
new ThreadPoolExecutor.DiscardOldestPolicy()); // When new work is submitted discard oldest
Then when your tasks come in just submit them to this executor, if there is already a queued job it will be replaced with the new one
latestTaskExecutor.execute(() -> doUpdate()));
Here is a example app showing this working
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class LatestUpdate {
private static final Executor latestTaskExecutor = new ThreadPoolExecutor(1, 1, // Single threaded
30L, TimeUnit.SECONDS, // Keep alive, not really important here
new ArrayBlockingQueue<>(1), // Single element queue
new ThreadPoolExecutor.DiscardOldestPolicy()); // When new work is submitted discard oldest
private static final AtomicInteger counter = new AtomicInteger(0);
private static final Random random = new Random();
public static void main(String[] args) {
LatestUpdate latestUpdate = new LatestUpdate();
latestUpdate.run();
}
private void doUpdate(int number) {
System.out.println("Latest number updated is: " + number);
try { // Wait a random amount of time up to 5 seconds. Processing the update takes time...
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void run() {
// Updates a counter every second and schedules an update event
Thread counterUpdater = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000L); // Wait one second
} catch (InterruptedException e) {
e.printStackTrace();
}
counter.incrementAndGet();
// Schedule this update will replace any existing update waiting
latestTaskExecutor.execute(() -> doUpdate(counter.get()));
System.out.println("New number is: " + counter.get());
}
});
counterUpdater.start(); // Run the thread
}
}
This also covers the case for GUIs where once updates stop arriving you want the GUI to become eventually consistent with the last event received.
public class LatestTaskExecutor implements Executor {
private final AtomicReference<Runnable> lastTask =new AtomicReference<>();
private final Executor executor;
public LatestTaskExecutor(Executor executor) {
super();
this.executor = executor;
}
#Override
public void execute(Runnable command) {
lastTask.set(command);
executor.execute(new Runnable() {
#Override
public void run() {
Runnable task=lastTask.getAndSet(null);
if(task!=null){
task.run();
}
}
});
}
}
#RunWith( MockitoJUnitRunner.class )
public class LatestTaskExecutorTest {
#Mock private Executor executor;
private LatestTaskExecutor latestExecutor;
#Before
public void setup(){
latestExecutor=new LatestTaskExecutor(executor);
}
#Test
public void testRunSingleTask() {
Runnable run=mock(Runnable.class);
latestExecutor.execute(run);
ArgumentCaptor<Runnable> captor=ArgumentCaptor.forClass(Runnable.class);
verify(executor).execute(captor.capture());
captor.getValue().run();
verify(run).run();
}
#Test
public void discardsIntermediateUpdates(){
Runnable run=mock(Runnable.class);
Runnable run2=mock(Runnable.class);
latestExecutor.execute(run);
latestExecutor.execute(run2);
ArgumentCaptor<Runnable> captor=ArgumentCaptor.forClass(Runnable.class);
verify(executor,times(2)).execute(captor.capture());
for (Runnable runnable:captor.getAllValues()){
runnable.run();
}
verify(run2).run();
verifyNoMoreInteractions(run);
}
}
This answer is a modified version of the one from DD which minimzes submission of superfluous tasks.
An atomic reference is used to keep track of the latest event. A custom task is submitted to the queue for potentially processing an event, only the task that gets to read the latest event actually goes ahead and does useful work before clearing out the atomic reference to null. When other tasks get a chance to run and find no event is available to process, they just do nothing and pass away silently. Submitting superfluous tasks are avoided by tracking the number of available tasks in the queue. If there is at least one task pending in the queue, we can avoid submitting the task as the event will be handled when an already queued task is dequeued.
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class EventExecutorService implements Executor {
private final Executor executor;
// the field which keeps track of the latest available event to process
private final AtomicReference<Runnable> latestEventReference = new AtomicReference<>();
private final AtomicInteger activeTaskCount = new AtomicInteger(0);
public EventExecutorService(final Executor executor) {
this.executor = executor;
}
#Override
public void execute(final Runnable eventTask) {
// update the latest event
latestEventReference.set(eventTask);
// read count _after_ updating event
final int activeTasks = activeTaskCount.get();
if (activeTasks == 0) {
// there is definitely no other task to process this event, create a new task
final Runnable customTask = new Runnable() {
#Override
public void run() {
// decrement the count for available tasks _before_ reading event
activeTaskCount.decrementAndGet();
// find the latest available event to process
final Runnable currentTask = latestEventReference.getAndSet(null);
if (currentTask != null) {
// if such an event exists, process it
currentTask.run();
} else {
// somebody stole away the latest event. Do nothing.
}
}
};
// increment tasks count _before_ submitting task
activeTaskCount.incrementAndGet();
// submit the new task to the queue for processing
executor.execute(customTask);
}
}
}
Though I like James Mudd's solution but it still enqueues a second task while previous is running which might be undesirable. If you want to always ignore/discard arriving task if previous is not completed you can make some wrapper like this:
public class DiscardingSubmitter {
private final ExecutorService es = Executors.newSingleThreadExecutor();
private Future<?> future = CompletableFuture.completedFuture(null); //to avoid null check
public void submit(Runnable r){
if (future.isDone()) {
future = es.submit(r);
}else {
//Task skipped, log if you want
}
}
}
Is there a nice way to stop the repetition of task from within the task itself when running in a ScheduledExecutorService?
Lets say, I have the following task:
Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
// ??? cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
From outside, it is easy to cancel via f.cancel(), but how can I stop the repetition at the specified place? (Passing the Future through an AtomicReference is not safe, because there is a potential window when the scheduleAtFixedRate returns f late and the variable is set late too, and the task itself might already run, seeing a null in the reference.)
When a repeating task throws an Exception or Error, it is placed in the Future and the task is not repeated again. You can throw a RuntimeException or Error of your choice.
Instead of using an anonymous inner class you can use a named class which can then have a property for the Future object you get from the Executor when you schedule a task.
abstract class FutureRunnable implements Runnable {
private Future<?> future;
/* Getter and Setter for future */
}
When you schedule a task you can then pass the Future to the Runnable.
FutureRunnable runnable = new FutureRunnable() {
public void run() {
if (/* abort condition */)
getFuture().cancel(false);
}
};
Future<?> future = executor.scheduleAtFixedRate(runnable, ...);
runnable.setFuture(future);
Maybe you will have to make sure, that the task is not executed before the Future has been set, because otherwise you will get a NullPointerException.
It seems like bad design for the Runnable to know anything about the executor it is running in, or to throw an error if reaching 10 is not an error state is a hack.
Can you do the loop to 10 outside of the scheduling and execution? This may require using a non-scheduling executor as you'd be scheduling them manually yourself.
Here is another way, that's even Thread safe;
final Future<?>[] f = {null};
f[0]= scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
Future<?> future;
while(null==(future = f[0])) Thread.yield();//prevent exceptionally bad thread scheduling
future.cancel(false);
return;
//cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
Just saw this now... because I wanted to do the same thing... here is my solution, I suspect this is threadsafe.
First create a container for the Future:
public static class Cancel {
private ScheduledFuture<?> future;
public synchronized void setFuture(ScheduledFuture<?> future) {
this.future = future;
}
public synchronized void stop() {
LOG.debug("cancelling {}", future);
future.cancel(false);
}
}
And then the future code:
final Cancel controller = new Cancel();
synchronized (controller) {
ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(() -> {
if (<CONTINUE RUNNING CONDITION) {
} else {
// STOP SCHEDULABLE FUTURE
controller.stop();
}
}, startTime, timeBetweenVisbilityChecks);
controller.setFuture(future);
}
}
So notice how the stop will not be callable until the future has been created and the future has been set on the controller.
Bear in mind that the Runnable is the anomymous inner class and this will get run in a different thread altogether.