On executing the following code, the statement System.out.println("completed"); gets executed before the executor even though delay is set to 0. Why is it so? How can the order be maintained here?
public class TestMyClass {
private static int count = 0;
public static void main(String args[]) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable periodicTask = () -> {
try {
List<String> lines = Files.readAllLines(new File("E:\\MyFile.log").toPath());
String key = "FIND ME";
System.out.println("text not found");
for (String line : lines) {
if (line.contains(key)) {
count++;
System.out.println("found text ..." + count);
executor.shutdown();
}
}
} catch (IOException e) {
e.printStackTrace();
}
};
executor.scheduleAtFixedRate(periodicTask, 0, 5, TimeUnit.SECONDS);
System.out.println("completed");
}
}
Checking the condition while(!executor.isTerminated()) does the job. It ensures the next statements are executed only after the executor has done its job.
The reason is in the nature of multi-tasking/threading. The ScheduledExecutorService starts a new thread that executes your Runnable. Independently from that your main program continues its work in its own/original thread.
Both threads, the main and the runnable, will be processed in parallel.
In your case, the System.out.println("completed"); is faster in the execution then the Runnable that reads a file.
Now it depends on what you want to achieve. As you wrote already you can block your main program, e.g. with a loop and wait for the executor to finish all execution. But this is not what you usually do because then you could just execute the code in the same thread.
Typically you use multi-threading to execute code in parallel or to not block a task/thread, e.g. calling an web service and continue to do some other stuff.
Related
I have an execute method which is running multiple test cases one by one, the test cases are passed in a list of Strings arrays.
I am trying to run this test cases in multi-threaded way, also writing data in CSV file in parallel.
Here is what I have done but it seems that the code is not working in a multithreaded way. I have passed nThread 2,5,7 in newFixedThreadPool() but it is taking the same time to execute the code.
private void executeTest(List<String[]> inputArray) throws ExecutionException, InterruptedException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads);//2, 5, 7
long start = System.currentTimeMillis();
for (String[] listOfArray : inputArray) {
Callable c2 = new Callable() {
public ApiResponse call() {
response = runTestCase(listOfArray);
try {
csvWriter.writeCsv(listOfArray[0], response);
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
};
System.out.println("nThread :"+nThreads);
Future<ApiResponse> result = executor.submit(c2);
result.get();
}
long stop = System.currentTimeMillis();
long timeTaken = stop - start;
System.out.println("Total time taken :"+timeTaken+"No of Theads :"+nThreads);
}
The call to future result.get(0) blocks until the action is completed, so you are just executing the tasks one by one inside your loop - even if they are actioned on different threads by the executor service.
// result.get();
Instead remove the line above and await termination at the end so that the full number of threads in your pool may receive tasks at same time, such as:
// All task submitted, mark for shutdown (only call after ALL submits done)
executor.shutdown();
// Wait for the executor service to finish
// You should consider how long this should be:
if (!executor.awaitTermination(whateverTimeIsReasonable, TimeUnit.SECONDS))
throw new RuntimeException("Test failed");
Tests that hiding exceptions are no help for testing, changing this:
e.printStackTrace();
to throw new UncheckedIOException(e); will ensure that all errors are reported.
The routine myProcessToRun() needs to be executed 100 times but there needs to be about a second delay between each execution.
The following FOR Loop is used in conjunction with the ScheduledThreadPoolExecutor object.
for (int n=0; n<100; n++)
{
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.schedule(new Runnable() {
#Override
public void run() {
myProcessToRun();
}
}, (n+2), TimeUnit.SECONDS);
}
This actually works fine but the threads still remain.
Using JVisualVM the number of Threads increases by 100 threads when the routine is executed. When the routine finishes, the 100 threads still remain.
Clicking the "Perform GC" button doesn't clean them up so Java still believe they should exist.
How do these threads get cleaned up using an example like above?
---Edited---
I noticed the ScheduledThreadPoolExecutor was being instantiated within the Loop which was a terrible idea. After moving it outside the LOOP the threads created weren't so bad.
After attempting to implement the solution there was unexpected behavior.
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
for (int n=0; n<100; n++)
{
//final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
executor.schedule(new Runnable() {
#Override
public void run() {
doAddNewCondSet();
}
}, (n+2), TimeUnit.SECONDS);
}
try
{
executor.shutdown();
if (!executor.awaitTermination(400, TimeUnit.SECONDS))
executor.shutdownNow();
} catch (InterruptedException e1)
{
e1.printStackTrace();
}
With the modified code, it would immediate stop all the processes with the shutdown and nothing was executed.
With the executor.shutdown(); commented out and just using the awaitTermination(), the program just hung and after a few minutes, all the processes kicked off at the same time without delay which resulted in errors.
I suspect my implementation was wrong.
There are a number of ways that you can do this. You can view some of them here:
https://www.baeldung.com/java-executor-wait-for-threads
My personal favorite is the CountDownLatch:
Next, let’s look at another approach to solving this problem – using a
CountDownLatch to signal the completion of a task.
We can initialize it with a value that represents the number of times
it can be decremented before all threads, that have called the await()
method, are notified.
For example, if we need the current thread to wait for another N
threads to finish their execution, we can initialize the latch using
N:
ExecutorService WORKER_THREAD_POOL
= Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
WORKER_THREAD_POOL.submit(() -> {
try {
// ...
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// wait for the latch to be decremented by the two remaining threads
latch.await();
This code I have is not executing tasks in parallel,
it only executes the code in this case once (whatever is in the for loop, but it should be 2) :
public class mqDirect {
public static void main(String args[]) throws Exception {
int parallelism = 2;
ExecutorService executorService =
Executors.newFixedThreadPool(parallelism);
Semaphore semaphore = new Semaphore(parallelism);
for (int i = 0; i < 1; i++) {
try {
semaphore.acquire();
// snip ... do stuff..
semaphore.release();
} catch (Throwable throwable) {
semaphore.release();
}
executorService.shutdownNow();
}
}
}
In Java the main way to make code work in parallel is to create a Thread with a new Runnable as a constructor parameter. You then need to start it.
There are many tutorials to help you get this to happen properly.
As your code stands you are merely creating an ExecutorService (and not using it), creating a Semaphore (which should be done in the thread but isn't), performing some process and then shutting down the Executor.
BTW: ShutDownNow is probably not what you want, you should just use ShutDown.
OK, So I found this good tutorial
http://programmingexamples.wikidot.com/threadpoolexecutor
And I have done something like
public class mqDirect {
int poolSize = 2;
int maxPoolSize = 2;
long keepAliveTime = 10;
ThreadPoolExecutor threadPool = null;
final ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(
5);
public mqDirect()
{
threadPool = new ThreadPoolExecutor(poolSize, maxPoolSize,
keepAliveTime, TimeUnit.SECONDS, queue);
}
public void runTask(Runnable task)
{
threadPool.execute(task);
System.out.println("Task count.." + queue.size());
}
public void shutDown()
{
threadPool.shutdown();
}
public static void main (String args[]) throws Exception
{
mqDirect mtpe = new mqDirect();
// start first one
mtpe.runTask(new Runnable()
{
public void run()
{
for (int i = 0; i < 2; i++)
{
try
{
System.out.println("First Task");
runMqTests();
Thread.sleep(1000);
} catch (InterruptedException ie)
{
}
}
}
});
// start second one
/*
* try{ Thread.sleep(500); }catch(InterruptedException
* ie){}
*/
mtpe.runTask(new Runnable()
{
public void run()
{
for (int i = 0; i < 2; i++)
{
try
{
System.out.println("Second Task");
runMqTests();
Thread.sleep(1000);
} catch (InterruptedException ie)
{
}
}
}
});
mtpe.shutDown();
// runMqTests();
}
And it works !
But the problem is , this duplicated code ... runMqtests() is the same task, is there a way to specify it to run in parallel without duplicating the code?
The example I based this off is assuming each task is different.
This code I have is not executing tasks in parallel, it only executes the code in this case once (whatever is in the for loop, but it should be 2) :
Just because you instantiate an ExecutorService instance doesn't mean that things magically run in parallel. You actually need to use that object aside from just shutting it down.
If you want the stuff in the loop to run in the threads in the service then you need to do something like:
int parallelism = 2;
ExecutorService executorService = Executors.newFixedThreadPool(parallelism);
for (int i = 0; i < parallelism; i++) {
executorService.submit(() -> {
// the code you want to be run by the threads in the exector-service
// ...
});
}
// once you have submitted all of the jobs, you can shut it down
executorService.shutdown();
// you might want to call executorService.awaitTermination(...) here
It is important to note that this will run your code in the service but there are no guarantees that it will be run "in parallel". This depends on your number of processors and the race conditions inherent with threads. For example, the first task might start up, run, and finish its code before the 2nd one starts. That's the nature of threaded programs which are by design asynchronous.
If, however, you have at least 2 cores, and the code that you submit to be run by the executor-service takes a long time to run then most likely they will be running at the same time at some point.
Lastly, as #OldCurmudgeon points out, you should call shutdown() on the service which allows current jobs already submitted to the service to run as opposed to shutdownNow() which cancels and queued jobs and also calls thread.interrupt() on any running jobs.
Hope this helps.
I have these 5 simple thread that run a while loop:
flasherThread = new Thread(new Runnable() {
#Override
public void run() {
while(running.get()) {
// do network stuff
}
}
});
running is declared as private final AtomicBoolean running;.
I have this method:
public void stopFlasherThread() {
running.set(false);
}
My question is by setting the flag to false that stops the thread immediately ? Or do I need to call flasherThread.join() to make sure that the thread has stopped ?
The main issue is that I have 4-5 of these at a time.
So I have a loop such as:
for (int i = 0; i < 5; i++) {
ThreadArrayList.get(i).stopFlasherThread();
ThreadArrayList.get(i).join() // should I do this ?
}
Any help would be great! Thanks
According to the official documentation on join:
The join method allows one thread to wait for the completion of another. If t is a Thread object whose thread is currently executing,
t.join();
causes the current thread to pause execution until t's thread terminates.
So, no... or not necessarily, only if you need the result of the work of that thread to do something. The join will not stop / interrupt the thread, it will wait for it to finish its work. The stopFlasherThread will make the loop stop.
I would advise you to follow a different approach on using threads on Java using ExecutorService. For example:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<AtomicInteger> futureResult = executor.submit(new Callable<AtomicInteger>() {
#Override
public AtomicInteger call() {
// Here I return a random integer, but you can do your proper calculation
AtomicInteger atomicInteger =
new AtomicInteger(ThreadLocalRandom.current().nextInt());
System.out.println(Thread.currentThread().getName() + " " + atomicInteger);
return atomicInteger;
}
});
// Thread returns result, but continues to execute as it is a single thread pool
try {
System.out.println(Thread.currentThread().getName() + " " + futureResult.get());
} catch (InterruptedException e) {
// Handle exception properly
e.printStackTrace();
} catch (ExecutionException e) {
// Handle exception properly
e.printStackTrace();
}
// Stop all threads
executor.shutdownNow();
There I define an inline class that extends the Callable interface and implement the call method to perform a task in another thread. This returns the result of the computation in the variable futureResult which is a Future. Since executor is a thread pool, it continues to be available to take tasks even though our task here has already been resolved. To finish the whole thread pool loop you can do a executor.shutdownNow().
I am trying to learn the java concurrency API, and for my exercise i want to schedule a job to run periodically every X seconds. The job will compute a random number.
I want to get the result of the scheduled task as soon as it is finished.
I could not get this done only with the API so i hacked it.
Is there a way to do this better, without using low level mechanisms?
I would like to be able to remove the synchronization in MyRandomGiverTask.getResult() and instead use
something like the ScheduledFuture.get(). But in my code ScheduledFuture is never done/completed.
This is my current solution:
class A {
public static void main() {
MyRandomGiverTask task = new MyRandomGiverTask(200);
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
ScheduledFuture<Double> scheduledDouble =
(ScheduledFuture<Double>) scheduler
.scheduleAtFixedRate(task, 1, 4, TimeUnit.SECONDS);
while (true) {
System.out.println(" >> " + task.getResult());
}
}
public class MyRandomGiverTask implements Runnable {
MyRandomGiver giver = new MyRandomGiver();
int param;
double result;
public MyRandomGiverTask(int param) { this.param = param; }
#Override public void run() { result = giver.getRandom(param); }
public double getResult() {
try {
while (result == 0d) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return result;
} finally {
result = 0d;
}
}
}
}
Your task is scheduled at fixed rate. This means that until you cancel the task, it will be executed again and again by the executor with a fixed rate. The only thing that such a task can do is to have a side-effect. It can't return anything, since the future that is returned by the executor represents all the pending executions of the task. BTW, you'll notice that the schedule method takes a Callable as argument (which can result something), whereas the sceduleAtFixedRate method only takes a Runnable as argument (which returns void, thus can't return anything).
So, if you want to print the result of each execution, then simply make the task itself (the Runnable) print its result, or have the runnable put its result in a blocking queue, and have the main thread take from the queue. The main thread will thus be blocked untile some result is put in the queue.
If you want to get every random number computed, use a BlockingQueue. the scheduled tasks put()s new random numbers in the queue and whatever wants them can take() them.
also, if you were going to use something like your solution, you would want to use wait()/notify(), not sleep().