Stop a thread ScheduledThreadPoolExecutor after some condition occure - java

I want to have some thread pool, that runs some tasks every fixed amount of time (this thread pool keeps getting tasks all the time). Each task calls some API to get some value, which can be null. I want the task to run again (after fixed time) only if the returned value is null. Otherwise, I don't want this task to ever run again. Is there any way to achieve that?
The only thing I had in mind is to use ScheduledThreadPoolExecutor and kill the specific thread from within, but I didn't find a way to do that and I am not sure it's a good practice.
Thanks!

You can schedule tasks by one and check your condition before scheduling next task:
public class Solver {
final long delay = 500L;
String getSomeValue() {
if (Math.random() < 0.8) return "not-null";
return null;
}
void init() {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(8);
Runnable runnable = new Runnable() {
#Override
public void run() {
long time = System.currentTimeMillis();
String value = getSomeValue();
System.out.println("" + value + " " + System.currentTimeMillis());
if (value == null) {
executor.schedule(this, delay - (System.currentTimeMillis() - time), TimeUnit.MILLISECONDS);
}
}
};
executor.schedule(runnable, delay, TimeUnit.MILLISECONDS);
}
public static void main(String[] args) {
new Solver().init();
}
}

Related

Implementing threads/callable adds 50% to my execution time, why is this?

I'm currently learning multithreading, but I have some problems understanding what's going wrong in my code.
I'm trying to fill two lists with random data by calling my function threadPopulateList(). In my understanding, this should start two threads in parallel, as I call the method twice.
But, my execution time goes up by ~50% when using the threadmethod.
Code:
public class Main {
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.currentTimeMillis();
/**Populate lists after eachother gives --> 4211 ms */
// List<DATA>list1normal = populateNormal(9999999);
// List<DATA>list2normal = populateNormal(9999999);
/**Populate list simoultaniously/parralel --> 6500ms???*/
List<DATA>list1normal = threadPopulateList(9999999);
List<DATA>list2normal = threadPopulateList(9999999);
long stop = System.currentTimeMillis();
long executionTime = stop-start;
System.out.println(executionTime+" ms");
}
/**Method to populate list*/
static List<DATA> populateNormal(int amount){
List<DATA>data = new ArrayList<>();
Random rn = new Random();
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000),rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
}
/**Method to start a thread for each call so list will populate simoultiously*/
static List<DATA> threadPopulateList(int amount) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<DATA> data = new ArrayList<>();
Random rn = new Random();
Callable<List<DATA>> callable = () -> {
for (int i = 0; i < amount; i++) {
data.add(new DATA(rn.nextInt(1000), rn.nextInt(1000), rn.nextInt(1000)));
}
return data;
};
Future<List<DATA>> result = executor.submit(callable);
executor.shutdown();
return result.get();
}
}
Callable is the task to be performed. Your code has only one Callable so it can only be executed on one thread.
Even though you created a ThreadPool with two threads in it, since you have only one task, one of the threads is guaranteed to be idle.
In addition, you are filling out the list twice, so your one task is going to be twice as long as it was when you filled the list once.
I would try creating two Callables each to process 1/2 the data in the list; and, then scheduling them both. Once they are both done, combine the results into a final "output" list.
The reason your solution only adds 50% to the time, and not 100% to the time is because your benchmark probably includes the time to start the JVM and begin processing. This means that your overall breakdown of the original program was probably "execution time = startup time + processing time" where startup time was about 1/2 of the execution time.
You're actually creating two serialized tasks with internal threading that doesn't really do anything. If you want to parallelize, you need to try something more like this:
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
long start=System.nanoTime();
int amount = 9999999;
populateNormal(amount);
populateNormal(amount);
long stop = System.nanoTime();
System.out.println("Normal execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop - start)+"ms");
ExecutorService executor = Executors.newFixedThreadPool(2);
start = System.nanoTime();
final CountDownLatch latch = new CountDownLatch(2);
executor.submit(new Runnable() {
#Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
executor.submit(new Runnable() {
#Override
public void run() {
populateNormal(amount);
latch.countDown();
}
});
latch.await();
stop = System.nanoTime();
executor.shutdown();
System.out.println("Threaded execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop-start)+"ms");
}

ExecutorService and AtomicInteger : RejectedExecutionException

I want atomicInteger to have a value of 100 then the program terminates
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
AtomicInteger atomicInteger = new AtomicInteger(0);
do {
executor.submit(() -> {
System.out.println(atomicInteger.getAndAdd(10));
if (atomicInteger.get() == 100) {
//executor.shutdownNown();
}
});
} while (true);
}
I have error
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask#1d8d10a rejected from java.util.concurrent.ThreadPoolExecutor#9e54c2[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 10]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1374)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at java.util.concurrent.Executors$DelegatedExecutorService.submit(Executors.java:678)
How should I implement it.
There is no need to use AtomicInteger here, since your Runnable lambda function invocations are guaranteed to execute sequentially (by new SingleThreadExecutor). Also, your Runnable lambda code were to take any time to execute (e.g. 2ms), your main loop will queue up far more than 10 tasks needed to hit your limit. You can see this happen if you add a 2ms sleep inside your Runnable lambda function, and also add a counter to your do/while loop, and print the value of the counter out at the end to see how many instances Runnables you queued up.
Assuming that you wish to test this code with concurrent threads, you would need to replace the call to newSingleThreadPool with newFixedThreadPool. The approach your code takes is problematic when concurrent threads are being used. In the following code, I've switched to newFixedThreadPool, added a counter, so we can see how many tasks are queued, and added to short pauses in your Runnable lambda function, just to represent a small amount of work. When I execute this program, atomicInteger became greater than 13000 and the program crashed with java.lang.OutOfMemoryError: GC overhead limit exceeded That is because, your runnable function always adds 10 to atomicInteger regardless of it's current value. And also, the code queues up more tasks than it needs. Here's the code with these small changes that illustrate the problem.
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
AtomicInteger atomicInteger = new AtomicInteger(0);
int i=0;
do {
executor.submit(() -> {
pause(2); // simulates some small amount of work.
System.out.println("atomicInt="+atomicInteger.getAndAdd(10));
pause(2); // simulates some small amount of work.
if (atomicInteger.get() == 100) {
System.out.println("executor.shutdownNow()");
System.out.flush();
executor.shutdownNow();
}
});
if (atomicInteger.get() == 100) {
break;
}
} while (true);
System.out.println("final atomicInt="+atomicInteger.get());
System.out.println("final tasks queued="+i);
}
public static void pause(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ex) {
}
}
Here is a version that fixes the concurrency problems and moves the executor management out of the worker threads where it doesn't really belong:
private static int LIMIT = 100;
private static int INCREMENT = 10;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
AtomicInteger atomicInteger = new AtomicInteger(0);
for (int i=0; i < LIMIT/INCREMENT; i++) {
executor.submit(() -> {
pause(2);
System.out.println("atomicInt=" + atomicInteger.getAndAdd(INCREMENT));
System.out.flush();
pause(2);
});
}
executor.shutdown();
while (!executor.isTerminated()) {
System.out.println("Executor not yet terminated");
System.out.flush();
pause(4);
}
System.out.println("final atomicInt=" + atomicInteger.get());
}
public static void pause(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ex) {
}
}
You should just change your while loop to check for the condition that you needed and shutdown the executor after that

Terminate other Future tasks running in when condition is met in one for the Future Task

Using java 8
I'm trying to write a prog to download log files from diff servers and search a given text in these log files. I'm doing is synchronously right now. I want to do it in parallel and found out that it can be done using Future in java. I'm using apache.commons.io for downloading file from URL.
Here is code snippet:
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<XCluster>> clusterFutures = new ArrayList<>();
for(XCluster cluster: clusters) {
clusterFutures.add(executorService.submit(() -> {
return downloadAndSearch(textToSearch, cluster);
}));
}
//For now I'm not doing anything with returned value from Future
But now I want to terminate other download-search operation started under Future as given search is expected to be found in only one of the servers. So there is no need to continue on other Future tasks which I started. can any one suggest a way to do this? I'm using java 8, other options are also welcome. Thanks In Advance!
The ExecutorService has a shutdownNow method which will stop all threads and shut down the service.
Edit:
I made some experiments with shutDownNow and as I see it can't stop the threads as I thought. AFAIK It uses interrupts() but not all thread react to interrupt.
So the best alternative I can come up with:
First, create an Indicator class:
public static class Indicator{
private boolean isReady = false;
public void ready(){
isReady = true;
}
public boolean isReady(){
return isReady;
}
}
The threads you start should share one Indicator instance to communicate.
So you can create a Callable like this:
public static class Processor implements Callable<Integer> {
private volatile Indicator indicator;
private Integer number;
public Processor(Integer integer, Indicator isReady){
this.number = integer;
this.indicator = isReady;
}
#Override
public Integer call() throws Exception {
System.out.println("Thread started:" + Thread.currentThread().getId());
int counter = 0;
while (!indicator.isReady &&counter < number) {
// Make complicated things
Math.sin(counter);
counter++;
}
if(indicator.isReady){
//another thread finished
//delete resources
System.out.println("Thread interrupted: " + Thread.currentThread().getId() + " " + counter);
return -1;
} else {
System.out.println("Thread finished: " + Thread.currentThread().getId() + " " + counter);
indicator.ready();
return counter;
}
}
}
This way when the first thread is ready it can stop the others and they clean up after himselves.
I tried this as follows:
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> clusterFutures = new ArrayList<>();
Indicator indicator = new Indicator();
clusterFutures.add(executorService.submit(new Processor(100, indicator)));
clusterFutures.add(executorService.submit(new Processor(10000, indicator)));
clusterFutures.add(executorService.submit(new Processor(10000000,indicator)));
}
A sample output:
Thread started:11
Thread started:12
Thread finished: 11 100
Thread interrupted: 12 1001
Thread started:13
Thread interrupted: 13 0
Sidenote: the referenced classes don't have to be static inner classes just it was easier to make experiments in one file.
In terms of code, the simplest solution is to have a shutdown thread that cancels all the futures:
final ExecutorService executorService = Executors.newCachedThreadPool();
final ExecutorService shutdownService = Executors.newSingleThreadExecutor();
List<Future<XCluster>> clusterFutures = new ArrayList<>();
for(XCluster cluster: clusters) {
clusterFutures.add(executorService.submit(() -> {
boolean cancelOthers = false;
try {
XCluster result = downloadAndSearch(textToSearch, cluster);
cancelOthers = yourPredicateOfSuccess();
return result;
} finally {
if (cancelOthers) {
shutdownService.execute(() -> {
executorService.shutdownNow();
});
}
}
}));
}
The other thread and the try-finally is important because this makes sure that you won't cancel the almost-successful method run.

Java ScheduledExecutorService - Preventing Starvation in Multiple Parallel Tasks

I'm working on a program that needs to inspect multiple resources in parallel and periodically:
public class JobRunner {
private final SensorService sensorService;
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
public void run() {
sensorService.finalAll().forEach(sensor -> {
Runnable task = () -> {
// read and save new data to log
List<Double> data = sensor.fetchNewData();
this.save(data);
};
// execute every 10 sec
executor.scheduleWithFixedDelay(task, 0, 10, TimeUnit.SECONDS);
});
}
public void save(List<Double> data) {
// ...
}
}
The findAll call returns a list of about 50 sensors, but when I run the program I see that while all sensors are queried on the first period, only 2-3 are called on subsequent executions (e.g - at 20 sec, 30 sec, etc). I'm thinking that since some sensors return faster than others, they complete the task's waiting cycle earlier and are grabbed by the next thread in the pool, thereby starving the other tasks that are slower to finish.
How can I ensure all tasks (sensors) are given equal treatment? What's are some best practices here; should I use a job queue or a different concurrency mechanism? Thanks.
In your code there are N=count service.findAll() timers, which makes debugging and testing more difficult. Moreover there is no guarantee that old task will be executed and not overtaken by the new one in reasonable time. What if you
Use single timer which triggers sensors check 10s after last all sensors check completed
Go through sensors concurrently when check is triggered by the timer
Please, see the next code as an example. It prints 50 integers every 10 seconds and EOL afterwards. Parallelism is achieved with Stream API
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
IntStream.range(0, 50).parallel().forEach(i -> System.out.print(i + " "));
System.out.println();
}
}, 0, 10, TimeUnit.SECONDS);
You may replace ScheduledExecutorService with Timer to make code clearer. And, as an option, instead of using parallel streams you can use another ExecutorService, submitting next N tasks to it on Timer and waiting until they are completed:
ExecutorService workerExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
List<Future<Void>> futures = new ArrayList<>();
for (int i = 0; i < 50; i++) {
final int index = i;
Future<Void> future = workerExecutor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.print(index + " ");
return null;
}
});
futures.add(future);
}
for (Future<Void> future : futures) {
try {
future.get();
} catch (InterruptedException|ExecutionException e) {
throw new RuntimeException();
}
}
System.out.println();
}
}, 0, 10_000);

Running time of a job sent to a ExecutorService

Good day,
I am writing a program where a method is called for each line read from a text file. As each call of this method is independent of any other line read I can call them on parallel. To maximize cpu usage I use a ExecutorService where I submit each run() call. As the text file has 15 million lines, I need to stagger the ExecutorService run to not create too many jobs at once (OutOfMemory exception). I also want to keep track of the time each submitted run has been running as I have seen that some are not finishing. The problem is that when I try to use the Future.get method with timeout, the timeout refers to the time since it got into the queue of the ExecutorService, not since it started running, if it even started. I would like to get the time since it started running, not since it got into the queue.
The code looks like this:
ExecutorService executorService= Executors.newFixedThreadPool(ncpu);
line = reader.readLine();
long start = System.currentTimeMillis();
HashMap<MyFut,String> runs = new HashMap<MyFut, String>();
HashMap<Future, MyFut> tasks = new HashMap<Future, MyFut>();
while ( (line = reader.readLine()) != null ) {
String s = line.split("\t")[1];
final String m = line.split("\t")[0];
MyFut f = new MyFut(s, m);
tasks.put(executorService.submit(f), f);
runs.put(f, line);
while (tasks.size()>ncpu*100){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Iterator<Future> i = tasks.keySet().iterator();
while(i.hasNext()){
Future task = i.next();
if (task.isDone()){
i.remove();
} else {
MyFut fut = tasks.get(task);
if (fut.elapsed()>10000){
System.out.println(line);
task.cancel(true);
i.remove();
}
}
}
}
}
private static class MyFut implements Runnable{
private long start;
String copy;
String id2;
public MyFut(String m, String id){
super();
copy=m;
id2 = id;
}
public long elapsed(){
return System.currentTimeMillis()-start;
}
#Override
public void run() {
start = System.currentTimeMillis();
do something...
}
}
As you can see I try to keep track of how many jobs I have sent and if a threshold is passed I wait a bit until some have finished. I also try to check if any of the jobs is taking too long to cancel it, keeping in mind which failed, and continue execution. This is not working as I hoped. 10 seconds execution for one task is much more than needed (I get 1000 lines done in 70 to 130s depending on machine and number of cpu).
What am I doing wrong? Shouldn't the run method in my Runnable class be called only when some Thread in the ExecutorService is free and starts working on it? I get a lot of results that take more than 10 seconds. Is there a better way to achieve what I am trying?
Thanks.
If you are using Future, I would recommend change Runnable to Callable and return total time in execution of thread as result. Below is sample code:
import java.util.concurrent.Callable;
public class MyFut implements Callable<Long> {
String copy;
String id2;
public MyFut(String m, String id) {
super();
copy = m;
id2 = id;
}
#Override
public Long call() throws Exception {
long start = System.currentTimeMillis();
//do something...
long end = System.currentTimeMillis();
return (end - start);
}
}
You are making your work harder as it should be. Java’s framework provides everything you want, you only have to use it.
Limiting the number of pending work items works by using a bounded queue, but the ExecutorService returned by Executors.newFixedThreadPool() uses an unbound queue. The policy to wait once the bounded queue is full can be implemented via a RejectedExecutionHandler. The entire thing looks like this:
static class WaitingRejectionHandler implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);// block until capacity available
} catch(InterruptedException ex) {
throw new RejectedExecutionException(ex);
}
}
}
public static void main(String[] args)
{
final int nCPU=Runtime.getRuntime().availableProcessors();
final int maxPendingJobs=100;
ExecutorService executorService=new ThreadPoolExecutor(nCPU, nCPU, 1, TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(maxPendingJobs), new WaitingRejectionHandler());
// start flooding the `executorService` with jobs here
That’s all.
Measuring the elapsed time within a job is quite easy as it has nothing to do with multi-threading:
long startTime=System.nanoTime();
// do your work here
long elpasedTimeSoFar = System.nanoTime()-startTime;
But maybe you don’t need it anymore once you are using the bounded queue.
By the way the Future.get method with timeout does not refer to the time since it got into the queue of the ExecutorService, it refers to the time of invoking the get method itself. In other words, it tells how long the get method is allowed to wait, nothing more.

Categories

Resources