Understanding ThreadPoolExecutor internal working - java

I am having following code:
public class ExecFramework implements Runnable {
int i;
public ExecFramework() {
}
public ExecFramework(int i) {
this.i = i;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ExecutorService pool=new ThreadPoolExecutor(2, 10, 5000,TimeUnit.SECONDS, new ArrayBlockingQueue(2));
for (int i = 0; i < 20; i++) {
Runnable obj=new ExecFramework(i);
pool.execute(obj);
}
pool.shutdown();
while(pool.isTerminated()){
System.out.println("ExecutorService is terminated");
}
}
}
Is my knowledge for the way ThreadPoolExecutor works correct:
If NumberOfThreadRunning < CoreNumberOfThreads then ThreadPoolExecutor creates a new thread to complete the task.
If NumberOfThreadRunning > CoreNumberOfThreads then queue this task in BlockingQueue but if queue is full then create a new Thread only if
NumberOfThread < MaxNumberOfThreads.
Once the task is completed thread running that task is available for other task.
According to 3rd point. I should be able to execute 20 tasks using ThreadPoolExecutor.
Why Output of above code is?
pool-1-thread-5 6
pool-1-thread-4 5
pool-1-thread-3 4
pool-1-thread-1 0
pool-1-thread-2 1
pool-1-thread-6 7
pool-1-thread-7 8
pool-1-thread-8 9
pool-1-thread-9 10
pool-1-thread-10 11
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task executionFramework.ExecFramework#232204a1 rejected from java.util.concurrent.ThreadPoolExecutor#4aa298b7[Running, pool size = 10, active threads = 10, queued tasks = 2, completed tasks = 0]
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:1379)
at executionFramework.ExecFramework.main(ExecFramework.java:88)
pool-1-thread-8 2
pool-1-thread-6 3

The documentation says it: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
In section Rejected tasks.
In your case i would guess this :
when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated
happens.

Related

Why did CyclicBarrier.await(int timeout,TimeUnit unit) didn't throw TimeOutException here?

Talk is cheap. Show the code.
MyCyclicBarrier.java
public class MyCyclicBarrier extends Thread{
private CyclicBarrier cyclicBarrier;
public MyCyclicBarrier(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
#Override
public void run() {
System.out.println("Thread start." + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2); //biz code
System.out.println("Thread "+Thread.currentThread().getName()+" is waiting for the other Threads."+
"\n\t\t\t\tIt's parties is "+cyclicBarrier.getParties()+
"\n\t\t\t\tWaiting for "+cyclicBarrier.getNumberWaiting()+" Threads");
cyclicBarrier.await(3,TimeUnit.SECONDS);
} catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
e.printStackTrace();
}
System.out.println("Thread end."+Thread.currentThread().getName());
}
}
TestCyclicbarrier.java
public class TestCyclicbarrier1 {
public static void main(String[] args) {
int length = 5;
long start = System.currentTimeMillis();
CyclicBarrier cyclicBarrierWithRunnable = new CyclicBarrier(length, () -> {
System.out.println("the final reach Thread is " + Thread.currentThread().getName());
long end = System.currentTimeMillis();
System.out.println("cost totally :" + (end - start) / 1000 + "s");
});
for (int i = 0; i < length; i++) {
if (i != 4) {
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} else {
try {
TimeUnit.SECONDS.sleep(2);
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output:
Thread start.Thread-1
Thread start.Thread-0
Thread start.Thread-2
Thread start.Thread-3
Thread Thread-0 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread Thread-3 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread start.Thread-4
Thread Thread-1 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread Thread-2 is waiting for the other Threads.
It's parties is 5
Waiting for 1 Threads
Thread Thread-4 is waiting for the other Threads.
It's parties is 5
Waiting for 4 Threads
the final reach Thread is Thread-4
cost totally :4s
Thread end.Thread-4
Thread end.Thread-0
Thread end.Thread-3
Thread end.Thread-2
Thread end.Thread-1
I am searching for a long time on net. But no similar answer. Please help or try to give some ideas! And I just start to learn CyclicBarrier.
I wonder if I have misunderstood CyclicBarrier.await(int timeout,TimeUnit unit). Threads 0 through 3 have already reached the barrier point that cost 2s.In the same time the final Thread started after 2s of waiting.After 1 second number 0 to 3 Threads reach the specified timeout which number 4 thread still excuted its own code. Here is the question: Why did CyclicBarrier.await(int timeout, TimeUnit unit) didn't throw TimeOutException here?
Threads 0 through 3 have already reached the Barrier point that cost 2s.
This is correct.
In the same time the final Thread started after 2s of waiting.
Correct. Note, by the time this thread starts, other 4 threads are awaiting the CB (3 secs timeout i.e., we have 3 secs until a TimeoutException can occur).
But thread 4 sleeps for only 2 seconds in the run method (we still have only 1 sec until the TimeoutException).
When it comes to await, it is the last thread - so it doesn't have to wait anymore. Hence the barrier action gets run and others are unblocked - from javadoc,
If the current thread is the last thread to arrive, and a
non-null barrier action was supplied in the constructor, then the current thread runs the action before allowing the other threads to continue.
If you make sleep for four seconds before starting thread-4, you would get a TimeoutException.
try {
TimeUnit.SECONDS.sleep(4);
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} catch (InterruptedException e) {
e.printStackTrace();
}
You seem to think that the timeout starts when the thread starts:
Threads 0 through 3 have already reached the Barrier point that cost 2s.
After 1 second number 0 to 3 Threads reach the specified timeout
This is wrong. When you call
cyclicBarrier.await(3,TimeUnit.SECONDS);
it doesn't matter how long it took the threads to reach that point - the timeout is 3 seconds from the moment the method cyclicBarrier.await() is called.
Since thread 4 has only an additional delay of 2 seconds it still arrives in time.
To clarify further this is what the timeline looks like:
t=0s
main() creates the CyclicBarrier and starts threads 0 to 3
the threads 0 to 3 start and call TimeUnit.SECONDS.sleep(2);
main calls TimeUnit.SECONDS.sleep(2);
t=2s
main() starts thread 4
the threads 0 to 3 awake, print out something and then call cyclicBarrier.await(3,TimeUnit.SECONDS); which means that they will be interrupted at t=5s (t=2s + 3s)
thread 4 stars and calls TimeUnit.SECONDS.sleep(2);
t=4s
thread 4 awakes, prints out something and then calls cyclicBarrier.await(3,TimeUnit.SECONDS);.
since now all threads are within cyclicBarrier.await(3,TimeUnit.SECONDS);, the condition for the CyclicBarrier is fulfilled and all threads continue
the timeout for thread 4 doesn't get used (because it is the last thread to reach the CyclicBarrier)
for threads 0 to 3 the timeout at t=5s is never reached

What is the real time benefits of creating Thread in Java?

class ThreadDemo extends Thread
{
public void run()
{
for(int i =0; i<5;i++)
{
System.out.println(i);
}
}
}
class ThreadApp
{
public static void main(String args[])
{
ThreadDemo thread1 = new ThreadDemo();
thread1.start();
ThreadDemo thread2 = new ThreadDemo();
thread2.start();
ThreadDemo thread3 = new ThreadDemo();
thread3.start();
}
}
Output:
0
2
3
1
4
1
2
4
3
0
0
1
2
3
4
By default, Java applications are single thread application. We are going for the concept called multithreading to share the work. Means, instead of doing the work with one thread (Main thread) if we create the thread, then it will simplifies the work. I understood this thing theoretically. My doubt arises when I start coding.
In the above program I have created 3 threads. If 3 threads are working on the same logic (iteration and printing the values by using for loop) why it is giving 3 separate output instead of giving one set of values from 0 to 4?
Duplicating the work, not sharing the work
You said:
We are going for the concept called multithreading to share the work.
But you did not share the work. You repeated the work. Instead of running a for loop once, you ran a for loop three times, once in each of three threads.
You asked:
why it is giving 3 separate output instead of giving one set of values from 0 to 4?
If a school teacher asks each of three pupils to write the alphabet on the board, we would end up not with 26 letters but with 78 letters (3 * 26). Each pupil would be looping through the letters of the alphabet. Likewise, each of your three threads looped through the count of zero to four.
Your for loop is local to (within) your task code. So each thread runs all of that code starting at the top. So the for loop executes three times, one per thread.
Beware: System.out prints out-of-order
Sending text to System.out via calls to println or print does not result in text appearing immediately and in the order sent. The lines of text you send may appear out of order.
When examining a sequence of statements, always include a timestamp such as java.time.Instant.now(). Then study the output. You may need to manually re-order the outputs using a text editor to see the true sequence.
You can see the out-of-chronological-order lines in my own example output below.
Executor service
In modern Java we no longer need address the Thread class directly. Generally best to use the Executors framework. See Oracle Tutorial.
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Counter
{
public static void main ( String[] args )
{
ExecutorService executorService = Executors.newCachedThreadPool();
Runnable task = new Runnable()
{
#Override
public void run ( )
{
for ( int i = 0 ; i < 5 ; i++ )
{
System.out.println( "i = " + i + " at " + Instant.now() + " on thread " + Thread.currentThread().getName() );
}
}
};
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
// Let our program run a while, then gracefully shutdown the executor service.
// Otherwise the backing thread pool may run indefinitely, like a zombie 🧟‍.
try { Thread.sleep( Duration.ofSeconds( 5 ).toMillis() ); }catch ( InterruptedException e ) { e.printStackTrace(); }
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.MINUTES ); } catch ( InterruptedException e ) { e.printStackTrace(); }
}
}
When run.
i = 0 at 2021-01-06T05:28:34.349290Z on thread pool-1-thread-1
i = 1 at 2021-01-06T05:28:34.391997Z on thread pool-1-thread-1
i = 0 at 2021-01-06T05:28:34.349246Z on thread pool-1-thread-2
i = 0 at 2021-01-06T05:28:34.349464Z on thread pool-1-thread-3
i = 1 at 2021-01-06T05:28:34.392467Z on thread pool-1-thread-3
i = 2 at 2021-01-06T05:28:34.392162Z on thread pool-1-thread-1
i = 2 at 2021-01-06T05:28:34.392578Z on thread pool-1-thread-3
i = 3 at 2021-01-06T05:28:34.392670Z on thread pool-1-thread-1
i = 3 at 2021-01-06T05:28:34.392773Z on thread pool-1-thread-3
i = 4 at 2021-01-06T05:28:34.393165Z on thread pool-1-thread-3
i = 1 at 2021-01-06T05:28:34.392734Z on thread pool-1-thread-2
i = 4 at 2021-01-06T05:28:34.392971Z on thread pool-1-thread-1
i = 2 at 2021-01-06T05:28:34.395138Z on thread pool-1-thread-2
i = 3 at 2021-01-06T05:28:34.396407Z on thread pool-1-thread-2
i = 4 at 2021-01-06T05:28:34.397002Z on thread pool-1-thread-2
Project Loom
Project Loom promises to be bring to Java new features such as virtual threads (fibers), and making ExecutorService be AutoCloseable for use with try-with-resources to automatically shutdown.
Let's rewrite the above code to use Project Loom technologies. Preliminary builds are available now based on early-access Java 16.
Also, we can rewrite the anonymous class seen above with simpler lambda syntax.
Another difference from above: Virtual threads do not have a name. So we switch to using the id number of the thread to differentiate between threads running.
try
(
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
Runnable task = ( ) -> {
for ( int i = 0 ; i < 5 ; i++ )
{
System.out.println( "i = " + i + " at " + Instant.now() + " on thread " + Thread.currentThread().getId() );
}
};
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
}
// At this point, the flow-of-control blocks until all submitted tasks are done.
// And the executor service is also shutdown by this point.
When run.
i = 0 at 2021-01-06T05:41:36.628800Z on thread 17
i = 1 at 2021-01-06T05:41:36.647428Z on thread 17
i = 2 at 2021-01-06T05:41:36.647626Z on thread 17
i = 3 at 2021-01-06T05:41:36.647828Z on thread 17
i = 4 at 2021-01-06T05:41:36.647902Z on thread 17
i = 0 at 2021-01-06T05:41:36.628842Z on thread 14
i = 1 at 2021-01-06T05:41:36.648148Z on thread 14
i = 2 at 2021-01-06T05:41:36.648227Z on thread 14
i = 3 at 2021-01-06T05:41:36.648294Z on thread 14
i = 4 at 2021-01-06T05:41:36.648365Z on thread 14
i = 0 at 2021-01-06T05:41:36.628837Z on thread 16
i = 1 at 2021-01-06T05:41:36.648839Z on thread 16
i = 2 at 2021-01-06T05:41:36.648919Z on thread 16
i = 3 at 2021-01-06T05:41:36.648991Z on thread 16
i = 4 at 2021-01-06T05:41:36.649054Z on thread 16
Sharing state across threads
If you really wanted to share values across the threads, you define them outside the immediate task code.
In this next example, we define a class Counter that implements Runnable. As a Runnable we can pass an instance of this class to an executor service. We defined a member field, a ConcurrentMap (a thread-safe Map) that tracks each of our desired numbers 0-4. For each of those five numbers, we map to the id number of the virtual thread that was able to beat the other virtual threads to submitting that entry into our originally-empty map.
Be aware that we are submitting a single Counter object to all three threads. So all three threads have access to the very same ConcurrentMap object. That is why we must use a ConcurrentMap rather than a plain Map. Any resource shared across threads must be built to be thread-safe.
We are calling Thread.sleep to try to mix things up. Otherwise, the first thread might finish all the work while the main thread is still submitting to the second and third threads.
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
public class Counter implements Runnable
{
public ConcurrentMap < Integer, Long > results = new ConcurrentHashMap <>();
#Override
public void run ( )
{
try { Thread.sleep( Duration.ofMillis( 100 ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
Long threadId = Thread.currentThread().getId(); // ID of this thread.
for ( int i = 0 ; i < 5 ; i++ )
{
// Shake things up by waiting some random time.
try { Thread.sleep( Duration.ofMillis( ThreadLocalRandom.current().nextInt(1, 100) ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
results.putIfAbsent( i , threadId ); // Auto-boxing converts the `int` value of `i` to be wrapped as a `Integer` object.
}
}
}
Here is a main method to make our exercise happen.
public static void main ( String[] args )
{
Counter counter = new Counter();
try
(
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
executorService.submit( counter );
executorService.submit( counter );
executorService.submit( counter );
}
// At this point, the flow-of-control blocks until all submitted tasks are done.
// And the executor service is also shutdown by this point.
System.out.println( "counter.results = " + counter.results );
}
In the results of this particular run, we can see that the two threads number 16 and 17 had all the success in putting entries into our map. The third thread was not able to be the first to put in any of the five entries.
counter.results = {0=16, 1=17, 2=17, 3=16, 4=16}
Try to do some various tests and see by yourself what is coming and from where
public class ThreadApp {
public static void main(String args[]) throws InterruptedException {
ThreadDemo thread1 = new ThreadApp().new ThreadDemo("t1",4);
ThreadDemo thread2 = new ThreadApp().new ThreadDemo("t2",7);
thread2.start();
thread1.start();
ThreadDemo thread3 = new ThreadApp().new ThreadDemo("t3",2);
// wait till t1 &t2 finish run then launch t3
thread1.join();
thread2.join();
thread3.start();
}
class ThreadDemo extends Thread {
int stop;
public ThreadDemo(String name, int stop) {
super(name);
this.stop = stop;
}
public void run() {
for (int i = 0; i < stop; i++) {
System.out.println(this.getName() + ":" + i);
}
}
}
}
Possible Output:
t2:0
t2:1
t1:0
t2:2
t1:1
t2:3
t1:2
t2:4
t1:3
t2:5
t2:6
//due to join t3 start only after t1 & t2 finish their run
t3:0
t3:1
Related to benefits, just one hint Producer-Consumer problem ...

why can't Countdownlatch in java stops at given latch count?

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// -----------------------------------------------------
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(5); // coundown from 5 to 0
ExecutorService executor = Executors.newFixedThreadPool(2); // 2 Threads in pool
for(int i=0; i < 10; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
Output:
Started
Started
Started
Started
Started
Started
Started
Completed`
Started
Started
Started
In the above code "Completed" should be printed after 6 times "Started" as latch count downs to 5 - 0, why it is always 7th or 8th time? Have i understood wrong?
Your thread pool has size 2 and your Processor threads take 3 seconds to execute.
First two Processors threads are started, the both print Started and they finish 3 seconds later.
Then the next two are started and again they both print Started and finish 3 second later.
Then another two (5th and 6th) are started, print Started and 3 seconds later when one of them (or both) finishes. At this point there are multiple things that are going to happen at roughly the same time (so the order is kind of random):
The main thread resumes and prints Completed
7th Processor thread is started and prints Started
8th Processor thread is started and prints Started
Therefore, Completed is always going to be preceded by 6, 7 or 8 Started print outs.
So, CountDownLatch does not guarantee that it will resume the parent thread (here I mean the thread from which you have called latch.await();) execution as soon as the Count Down goes to 0. So, what happens when Count Down latch countdown to 0 that means now parent Thread can resume its work and that does not mean it will get the get the CPU then and there. So, it can resume that does not mean CPU schedule the parent thread as soon as the countdown to 0. If there are other threads then is there is a possibility that those can execute before the parent thread. In your case, it ensures that it will not execute before the 5 time printing Started but it does ensure that it will be exactly after printing 5 times Started. You may also observe at a certain execution of your code Completed is printing at end of all Started printing.

Restart thread once the threads inside it finished

I have thread x which I start like so:
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(() -> {
Inside x I have a CyclicBarrier with another 10 threads:
final CyclicBarrier _threadGate = new CyclicBarrier(10);
ArrayList<Thread> _threadList = new ArrayList<>();
Then I add the thread to the list
for (int i = 0; i < 10; i++) {
_threadList.add(new Thread() {
#Override
public void run() {
_threadGate.await();
//long processing code
So after the threads are ready I start them, it is important for them to start at the same time (well almost, looping takes time, even if its 0,01ms):
for (int i = 0; i < _threadList.size(); i++) {
_threadList.get(i).start();
}
Now, the end of x, the main thread, is like this:
}, 0, repeatTimer, TimeUnit.SECONDS);
If repeatTimer is 300 this means that it starts again the 10 threads after 5 minutes.
The time for the 10 threads to finish is an UNKNOWN amount, but it is under 5 minutes. Somewhere between 2 and 4 minutes for sure.
What I want to achieve
Once the 10 threads finish, restart X but with a delay of 5 seconds.
For this I have been thinking of setting the repeatTimer value to the time elapsed by the 10 threads + 5 seconds (I dont know how to do it, I dont know w hen last thread finishes its task), but is this correct? or is there another way of doing it?
I don't see the necessity of having SchedulingExecutorService here. You can just wait until all threads finish their job using CountDownLatch.
Here's a simple exapmple:
while (!stopped) {
CountDownLatch latch = new CountDownLatch(N);
// create and start your threads
latch.await(); // this method blocks until each Thread calls countDown()
// wait here 5 seconds if you want
}
Decrement the latch in last action of each thread:
public void run() {
_threadGate.await();
// thread actions
latch.countDown();
}

Why threads run sequentially instead of simulatenously in Java

The threads in the following code don't seem to run simultaneously. However if I change the number to 1 million or add a Thread.sleep(50); into the loop it runs simultaneously. Making the thread sleep produces homogeneous results while increasing number to one million makes each thread prints 50+ lines before switching to other thread. What is the exact reason for this?
class RunnableDemo implements Runnable {
int number = 4;
private Thread t;
private String threadName;
RunnableDemo(String name) {
threadName = name;
}
public void run() {
System.out.println("----------");
for (int i = number; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
}
}
public void start() {
System.out.println("Starting " + threadName);
t = new Thread(this, threadName);
t.start();
}
}
public class Test {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
RunnableDemo R2 = new RunnableDemo("Thread-2");
R1.start();
R2.start();
}
}
This is the output produced by the code when number is 4:
Starting Thread-1
Starting Thread-2
----------
Thread: Thread-1, 4
Thread: Thread-1, 3
Thread: Thread-1, 2
Thread: Thread-1, 1
----------
Thread: Thread-2, 4
Thread: Thread-2, 3
Thread: Thread-2, 2
Thread: Thread-2, 1
System.out.println is buffered. You cannot therefore use it to test thread simultaneity.
Let's assume your machine has a single processor. Only one thread can run at any one time. If multiple processes are running they each receive a slice of time on the processor and will then be swapped out by some scheduling algorithm.
In your case when the number is 4 a thread can complete its work before being swapped out. Once done any other thread in the waiting state can run.
T1 > starts > executes > terminates
T2 > starts > executes > terminates
When you increase the number to a million a thread can execute only part of its work in the time allocated by the scheduler. Once this time is up it will be swapped out by the scheduler and another thread in the waiting state will run.
T1 > starts > executes for time x > moved to waiting state
T2 > starts > executes for time x > moved to waiting state
T1 > resumes > executes for time x > moved to waiting state
T2 > resumes > executes for time x > moved to waiting state
......
T1 > terminates
T2 > terminates
Simarily, when you request your thread sleeps for x then another thread can be moved to the running state.
http://tinyurl.com/o8f3ogx
Threads don't neccessarily switch after each instruction. It is perfectly possible for a thread to execute entire loop before switching to another. Adding sleep prolongs the execution and increases likelihood of context switch.

Categories