I want to know that when a program waits for Future object of one thread, will other threads continue their execution.
I have tried the below sample, it seems when my program is waiting for one thread, other threads are not continuing their execution. Please tell me whether this is correct or is there any issues with my code for handling threads.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w);
while(!future.isDone())
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Below is my worker class:
public class Worker implements Callable<String> {
#Override
public String call() throws Exception {
// TODO Auto-generated method stub
Thread.sleep(3000);
return Thread.currentThread().getName();
}
}
I am getting the below results(Added date time to show that the results are not parallel):
2019-01-04T16:34:22.647 pool-1-thread-1
2019-01-04T16:34:25.661 pool-1-thread-2
2019-01-04T16:34:28.673 pool-1-thread-3
2019-01-04T16:34:31.685 pool-1-thread-1
2019-01-04T16:34:34.699 pool-1-thread-2
The problem
You presented the code which from main thread perspective waits (2) for each execution before submitting new task (1). In other words: in main thread you submit the task, wait for complete execution in main thread and submit next task after.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w); // (1)
while(!future.isDone()) // (2)
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Solution
To solve the issue you should (from main thread perspective) submit all tasks without waiting and then wait for results from executor service.
Example: https://stackoverflow.com/a/49746114/1815881
You can construct all tasks then call invokeAll() in ExecutorService.
Related
I have a task that will run many times with different values. I'd like to prevent it from executing 2 of the same tasks (Based on the string value) at the same time. Below is an example of the strings. These values will change, but for simplicity I have included these values below in the example. I submit these tasks via an ExecutorService The tasks run, but the 2nd hi blocks the other tasks from running. So 4/5 tasks run concurrently. Once the lock is released from the first hi the 5th tasks continues and the other tasks continue fine. Is there a way to prevent this type of blocking of the task so that the other 3 tasks can run before it so there is no queuing until there is actually 5 tasks running concurrently.
Submission of the tasks:
executor.submit(new Task("hi"));
executor.submit(new Task("h"));
executor.submit(new Task("u"));
executor.submit(new Task("y"));
executor.submit(new Task("hi"));
executor.submit(new Task("p"));
executor.submit(new Task("o"));
executor.submit(new Task("bb"));
The Task is simple. It just prints out the string:
Lock l = getLock(x);
try {
l.lock();
System.out.println(x);
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(Task.class.getName()).log(Level.SEVERE, null, ex);
}
} finally {
l.unlock();
}
I've updated the post to allow for things to be more clearly understood...
To avoid blocking a thread, you have to ensure that the action doesn’t even run before the other. For example, you can use a CompletableFuture to chain an action, to be scheduled when the previous has been completed:
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
for(int i = 0; i < 5; i++) submit("one", task("one"), es);
for(int i = 0; i < 5; i++) submit("two", task("two"), es);
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(26));
es.shutdown();
}
static Runnable task(String x) {
return () -> {
System.out.println(x);
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
};
}
static final ConcurrentHashMap<String, CompletableFuture<Void>> MAP
= new ConcurrentHashMap<>();
static final void submit(String key, Runnable task, Executor e) {
CompletableFuture<Void> job = MAP.compute(key,
(k, previous) -> previous != null?
previous.thenRunAsync(task, e): CompletableFuture.runAsync(task, e));
job.whenComplete((v,t) -> MAP.remove(key, job));
}
The ConcurrentHashMap allows us to handle the cases as atomic updates
If no previous future exists for a key, just schedule the action, creating the future
If a previous future exists, chain the action, to be scheduled when the previous completed; the dependent action becomes the new future
If a job completed, the two-arg remove(key, job) will remove it if and only if it is still the current job
The example in the main method demonstrates how two independent actions can run with a thread pool of two threads, never blocking at thread.
StopWatch sw = new StopWatch();
sw.start();
ExecutorService executor = Executors.newFixedThreadPool(MYTHREADS);
for (int i = 0; i < MYTHREADS; i++) {
Runnable worker = new SingleConnectionRunnable();
executor.execute(worker);
}
sw.stop();
System.out.println("total time"+sw.toString());
sw.reset();
sw.start();
for (int i = 0; i < MYTHREADS; i++) {
Runnable worker2 = new PooledConnectionRunnable();
executor.execute(worker2);
}
executor.shutdown();
executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
while (!executor.isTerminated()) {
}
sw.stop();
System.out.println("total time"+sw.toString());
I am trying to run some perf tests on the code above. I am trying to use the same executor on different Runnable and measure the time. But it doesn't quite work. the first "total time" is not correct which is in milliseconds.
I want to print the elapsed time on the first loop then print the second loop. Not sure how I can wait executor to finish the first one then restart the executor.
What is the correct way to get this done?
First, awaitTermination will block until all tasks terminate. Is there any particular reason that you use a while loop check after waiting potentially 70 years?
Anyways, to answer your question, in order to wait for the first run to finish, you should use a CountDownLatch to signal completion of each thread and await for them in the main thread until they finish. You can also use a CyclicBarrier to await until all your threads are ready to go before starting timing, like so:
...
CountDownLatch latch = new CountDownLatch(MYTHREADS);
CyclicBarrier cb = new CyclicBarrier(MYTHREADS, new Runnable() {
#Override public void run() {
sw.start();
}
});
for (...) {
Runnable worker = ...
executor.execute(new Runnable() {
#Override public void run() {
try {
cb.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
worker.run();
latch.countDown();
}
});
}
latch.await();
sw.stop();
...
I moved the sw.start() to the beginning of the for-loop to avoid measuring object allocation overhead to setup (probably won't be measured anyways since its in ms).
You can also reset the two concurrency classes to run an indefinite number of times.
What you are doing now is:
Start the stopwatch
Start a few threads
Read the stopwatch
You are not waiting for them to finish like you do with the second loop.
This is what you can do to fix this.
Make a callback method in the SingleConnectionRunnable.
This method will be called at the last point of this runnable (when you terminate it) and caught by the class that starts the loop (which is not method in the question but that is fine).
In this callback method you keep track of how many times it is called.
When it is called MYTHREAD amount of times you print the stopwatch time.
Now you know how long it will take until all started threads are finished.
I have following part of code:
protected ExecutorService parallelExecutor = Executors.newCachedThreadPool();
protected ExecutorService serialExecutor = Executors.newSingleThreadExecutor();
List<?> parallelCommands = new ArrayList<?>();
List<?> serialCommands = new ArrayList<?>();
List<Future<Boolean>> results = null;
LocalDateTime timed = LocalDateTime.now().plusSeconds(60);
results = parallelExecutor.invokeAll(parallelCommands);
results.addAll(serialExecutor.invokeAll(serialCommands));
Now I would like to check if both executors finish their job within a timeout or not:
while (LocalDateTime.now().isBefore(timed)) {
\\ here I need to check if meanwhile my threads finished
\\ if yes, break;}
How can I verify if the executors finished their job?
JDK documentation:
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();
}
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#awaitTermination-long-java.util.concurrent.TimeUnit-
Use a counter to keep track of each task that finishes. You can decrement and check by modifying tasks added to your task list or by using a CompletableFuture.
List<Callable<?>> tasks = ...
ExecutorService executor = ...
// Might want to add the size of your other task list as well
AtomicInteger counter = new AtomicInteger(tasks.size());
for (Callable<?> callable : tasks) {
results.add(executor.submit(new Callable() {
callable.call();
int value = counter.decrementAndGet();
if (value == 0) {
synchronized (this) {
OuterClass.this.notify();
}
}
});
}
long timed = System.currentTimeMillis();
synchronized (this) {
long timeLeft;
// Or however many millis your timeout is
while ((timeLeft = 60_000 - System.currentTimeMillis() - timed) > 0) {
this.wait(timeLeft);
}
}
What you want to do is wait until you run out of time on your main thread, while your tasks are executed by the executor. If a task finishes and it realizes that there are no tasks that haven't finished, it tells the waiting thread to continue. I use notify() instead of notifyAll() because no other threads should be waiting for this object except the main thread, but if you do have other threads, use the latter option.
Having -
for (int i = 0; i<10 ; i++) {
Runnable r = new Runnable(){...}
new Thread(r).start();
}
// I want to continue here only after all the subclass threads before exited .
...
How could I make sure all the subclass threads exited before I continue on after the for section ?
Does exist any solution besides keep all the Runnable's in a List<Runnable> and finally check its isAlive() for each element ?
How could I make sure all the subclass threads exited before I continue on after the for section ?
I'd use the ExecutorService classes. See the Java tutorial on them. Something like:
// create a thread pool with 10 workers
ExecutorService threadPool = Executors.newFixedThreadPool(10);
// or you can create an open-ended thread pool
// ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
threadPool.submit(new Runnable(){...});
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
Then you can wait for them to finish with:
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
If you still want to do your own threads then typically you keep them around in a List and call join() on each one of them:
List<Thread> threadList = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Runnable(){...});
thread.start();
threadList.add(thread);
}
// this waits for all of the threads to finish before continuing
for (Thread thread : threadList) {
thread.join();
}
Have a look at CountDownLatch. It is great for when you want to wait for N threads to be done with something.
I am trying to implement the multithreaded approach using executor interface where i have produced multiple threads in main class
class Main
{
private static final int NTHREADS = 10;
public static void main(String[] args)
{
.........
String str = createThreads(document);
.............
}
public String createThreads(String docString)
{
........
.......
Map<String,String> iTextRecords = new LinkedHashMap<String, String>();
if(!iText.matches(""))
{
String[] tokenizedItext = iText.split("\\^");
ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);
for(int index = 0 ;index < tokenizedItext.length;index++)
{
Callable<Map<String,String>> worker = null;
Future<Map<String,String>> map = null;
if(tokenizedItext[index].matches("^[0-9.<>+-= ]+$") || tokenizedItext[index].matches("^\\s+$"))
{
iTextRecords.put(tokenizedItext[index],tokenizedItext[index]);
}
else
{
worker = new MultipleDatabaseCallable(tokenizedItext[index],language);
map = executor.submit(worker);
try
{
iTextRecords.putAll(map.get());
}
catch(InterruptedException ex)
{
ex.printStackTrace(System.out);
}
catch(ExecutionException ex)
{
ex.printStackTrace(System.out);
}
}
}
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated())
{
}
}
}
The Callable class is as
class MultipleDatabaseCallable implements Callable<Map<String,String>>
{
#Override
public Map<String, String> call() throws Exception {
System.out.println("Entering: "+Thread.currentThread().getName());
Map<String,String> map = new HashMap<String,String>();
for(int i =0;i<50000;i++)
{
for(int i1 = 0 ;i1<5000;i1++)
{
for(int i2 =0;i2 <500;i2++)
{
}
}
}
System.out.println("Exiting: "+Thread.currentThread().getName());
return map;
}
}
output I am getting is
Entering: pool-1-thread-1
Exiting: pool-1-thread-1
Entering: pool-1-thread-2
Exiting: pool-1-thread-2
Entering: pool-1-thread-3
Exiting: pool-1-thread-3
Entering: pool-1-thread-4
Exiting: pool-1-thread-4
Entering: pool-1-thread-5
Exiting: pool-1-thread-5
Entering: pool-1-thread-6
Exiting: pool-1-thread-6
While looking at the output it seems like only one thread is entering at a time in the call method and other thread enters only when previous one exist. However it is expected that the multiple threads should enter and execute call() method. Also when I am executing the same program by making NTHREADS = 1. it is taking same time as it is taking with NTHREADS =10
so it seems like the application is running as good as a single threaded application.please suggest whats wrong i am doing in implementation.
Thanks
When you call
map = executor.submit(worker);
the value returned map in this case is a Future. Meaning that it does not have a value, until the callable has returned one. Now when you call
iTextRecords.putAll(map.get());
What happens is that the current thread blocks (inside the map.get()) waiting for the callable to return (in the other thread).
Since you always wait for a callable to be finished (per map.get()) before submitting a new one (per executor.submit()) you enforce the sequential execution you observe.
In order to execute the tasks in parallel, you have to start them all before calling get for the first time. You could for instance create an ArrayList<Future<Map<String,String>>> futures = ... and then
do
futures.add(executor.submit(worker));
to submit the tasks (no need for the map variable) and create a second loop (after the for(int i ...) loop):
for(Future<Map<String,String>> f: futures) {
iTextRecords.putAll(f.get);
}
You must collect your futures while you submit the callables. Call get() on your futures only after you finish submitting.