I just have started learning threads and come upon misunderstanding of how they work.
Here is my class:
public class MyThread extends Thread {
private static int NUM = 0;
private int id;
public MyThread() {
id = NUM++;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new MyThread().start();
}
}
public void run() {
System.out.println(id + " started");
try {
Process p = Runtime.getRuntime().exec("javac -version");
p.waitFor();
} catch (Exception e) {
System.out.println("Call a doc!");
}
System.out.println(id + " finished");
}
}
/*
Just a sidenote.
I am creating new javac process just to slow an application down.
Simple System.out.println(…) is a way faster.
*/
Why do I always get all "… started" messages at first and after that "… finished" messages? No matter how many threads have I started, I always see:
0 started
1 started
2 started
3 started
4 started
5 started
6 started
7 started
8 started
9 started
0 finished
1 finished
3 finished
4 finished
8 finished
5 finished
2 finished
6 finished
9 finished
7 finished
Isn't the purpose of threads to parallelize execution?
Maybe I need to synchronize something? Or made careless mistake? Or…?
Explain, please.
UPDATE:
Why don't I see, let's say:
0 started
1 started
0 finished
2 started
1 finished
2 finished
Thank you all for treatment.
Looks ok. You can see from your output that the threads are interleaving. threads are getting started, get context-switched, and get picked by the scheduler, you can see where thread 8 jumps ahead of thread 5, for instance. If all the numbers were in order consistently it would be strange but this seems fine.
Use sleep time, like Peter Lawrey suggests, so you can alter how long each thread takes more easily. As your example stands, starting a process takes so much time it seems reasonable all your threads should get started before any finish.
The threads are parallel. Otherwise you would see each thread "finished" before the next one "started"
A simple way to slow down a thread is to use Thread.sleep(10*1000); to sleep for 10 seconds (10,000 milli-seconds)
EDIT: a simple way to see threads interleaving is to have a fixed size thread pool.
ExecutorService pool = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
final int id = i;
pool.submit(new Callable<Void>() {
public Void call() throws InterruptedException {
System.out.println(id + " started");
Thread.sleep(1000);
System.out.println(id + " finished");
return null;
}
});
}
Prints
0 started
1 started
2 started
3 started
0 finished
4 started
1 finished
5 started
2 finished
6 started
3 finished
7 started
4 finished
8 started
5 finished
6 finished
9 started
7 finished
8 finished
9 finished
If you put a simple loop to count from 1 to 20 in the run() method you may see the interleaving of the execution better.
There is a difference between multi-threading and parallel processing... check this out...
If you want to see a "random" starting and ending you might want to add a
Thread.sleep(new Random().nextInt(1000));
or similar to the threads.
Related
I have following code :
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyThread implements Runnable{
private List<Integer> myList;
public MyThread(List<Integer> list){
this.myList = list;
}
private void updateList(int i){
synchronized (myList) {
myList.add(i);
}
}
#Override
public void run() {
for( int i = 0; i < 1000000;i++){
updateList(i);
}
System.out.println("end: " + myList.size());
}
}
public class MyExecutor {
private List<Integer> taskList = new ArrayList<>();
private void launch(){
ExecutorService executorService= Executors.newFixedThreadPool(10000);
executorService.execute(new MyThread(taskList));
executorService.execute(new MyThread(taskList));
executorService.shutdown();
}
public static void main(String[] args) {
MyExecutor test = new MyExecutor();
test.launch();
}
}
the output should be : 2000000
I will get different result which means these two threads are replacing each other's value.
I can't figure out where is the problem, tried several modifications on this code but none of them has fixed the problem. (replaced with Vector / added synchronize in constructor / added volatile)
Why doesn't this code work correctly?
Edit
At both thread I expect to get 1000000
the output should be : 2000000
No, for three reasons:
You are printing two things, so the output won't be a single number.
It prints the size when each thread happens to have added 1000000 things; you know nothing about how much the other thread has done at this point.
You are not accessing the size in a synchronized way, so you are liable to get a non-up to date value.
You are getting
end: 1065878
end: 2000000
The first line is from the thread that has finished its job first. It shouldn't be exactly 1M, because several threads are working. It's reasonable to assume that by the time one first thread finishes adding its 1M, the other has added at least one.
The second line is always 2M (as you expected ) due to the synchronised method.
I guess the first thread should execute for the exact number I wanted, no more no less.
Things happened in parallel. The threads were running. Each was trying to invoke updateList: one entered, the others waited. There was no priority on who should be next, so the control over the method was being passed among all the workers in a rather random manner.
I bet you are still thinking of the sequential execution :) One thread runs the whole run method, prints 1M, the other takes a 1M-sized list and adds its portion.
To understand it better, add a print statement
private void updateList(int i) {
synchronized (myList) {
myList.add(i);
System.out.println(Thread.currentThread().getName() + " added " + i);
}
}
and reduce the number of elements to add by a task to, let's say, 10.
pool-1-thread-1 added 0
pool-1-thread-1 added 1
pool-1-thread-1 added 2
pool-1-thread-1 added 3
pool-1-thread-2 added 0
pool-1-thread-2 added 1
pool-1-thread-2 added 2
pool-1-thread-2 added 3
pool-1-thread-1 added 4
pool-1-thread-1 added 5
pool-1-thread-1 added 6
pool-1-thread-1 added 7
pool-1-thread-1 added 8
pool-1-thread-1 added 9
end: 14
pool-1-thread-2 added 4
pool-1-thread-2 added 5
pool-1-thread-2 added 6
pool-1-thread-2 added 7
pool-1-thread-2 added 8
pool-1-thread-2 added 9
end: 20
I am new to multithreading. I have a volatile variable currentPrimeNo and it will print the next prime number as implemented in run method for every new thread. But everytime I am getting currentPrimeNo as 0 for every thread. How should I keep the global variable currentPrimeNo updated?
public class Processor implements Runnable {
private int id;
private static volatile int currentPrimeNo = 0;
public Processor(int id) {
this.id = id;
}
#Override
public void run() {
System.out.println("Starting process id: " + id);
currentPrimeNo = Utils.generateNextPrime(currentPrimeNo);
System.out.println("Prime Number Associated with this thread is: " + currentPrimeNo);
System.out.println("Completed process id: " + id);
}
}
And the main class is:
public class MainClass {
#SuppressWarnings("resource")
public static void main(String[] args) {
System.out.println("****This is where the project starts*****");
Scanner reader = new Scanner(System.in);
System.out.print("Enter number of processes you want to create: ");
int n = reader.nextInt();
ExecutorService executor = Executors.newFixedThreadPool(n);
for(int i=1;i<=n; i++) {
executor.submit(new Processor(i));
}
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("****This is where the project ends*****");
}
}
Below is the generateNextPrime method from Util class:
public synchronized static int generateNextPrime(int currentPrime) {
int nextPrime = 2;
if (currentPrime <= 1) {
return nextPrime;
} else {
for (int i = currentPrime + 1;; i++) {
boolean notPrime = false;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
notPrime = true;
break;
}
}
if (notPrime == false) {
return i;
}
}
}
}
Below is the output I am getting:
****This is where the project starts*****
Enter number of processes you want to create: 4
Starting process id: 2
Starting process id: 3
Starting process id: 1
Starting process id: 4
Prime Number Associated with this thread is: 2
Prime Number Associated with this thread is: 2
Completed process id: 4
Completed process id: 1
Prime Number Associated with this thread is: 2
Completed process id: 2
Prime Number Associated with this thread is: 2
Completed process id: 3
****This is where the project ends*****
Since you have not shared the code for generateNextPrime here, it would be a bit difficult to point out where exactly the code is failing.
There is an inherent problem associated with this.
Edit after Util.generateNextPrime() was added.
When we use volatile keyword, all threads would see the current value and not the cached value of the variable. But in your code, volatile variable is defined inside Runnable implementation. Thus, it doesn't server for the purpose. It is true that run method calls generateNextPrime and passes the volatile variable but what the called method actually sees and works on is a copy of the variable and not the exact variable (reading more on pass by value vs pass by reference will be beneficial to understand this better). The aim here is to have a single variable whose value should be altered by the generateNextPrime call which will be done by each thread while running.
I moved the currentPrimeNo definition to Util class so that all threads see only one variable (and not a copy of it) and that too the real-time value of the volatile variable. The method generateNextPrime() was also altered a bit for sake of compactness. The output necessarily need not be in same order as you will not know the order of invocation of the worker threads.
Here is the code:
public class Processor implements Runnable {
private int id;
public Processor(int id) {
this.id = id;
}
#Override
public void run() {
System.out.println("Starting process id: " + id);
int currentPrimeNo = Utils.generateNextPrime();
System.out.println("Prime Number Associated with this thread " + id +" is: " + currentPrimeNo);
System.out.println("Completed process id: " + id);
}
}
public class Utils {
private static volatile int currentPrime = 0;
public static synchronized int generateNextPrime(){
currentPrime++;
if(currentPrime < 2){
currentPrime = 2;
return currentPrime;
}
for (int i = 2; i <currentPrime; i++) {
if(currentPrime%i == 0) {
currentPrime++;
i=2;
} else{
continue;
}
}
return currentPrime;
}
}
Output seen while benchtesting
Sample 1:
****This is where the project starts*****
Enter number of processes you want to create: 4
Starting process id: 3
Starting process id: 1
Starting process id: 2
Starting process id: 4
Prime Number Associated with this thread 3 is: 2
Prime Number Associated with this thread 1 is: 7
Completed process id: 1
Prime Number Associated with this thread 2 is: 3
Completed process id: 2
Prime Number Associated with this thread 4 is: 5
Completed process id: 3
Completed process id: 4
****This is where the project ends*****
Sample 2:
****This is where the project starts*****
Enter number of processes you want to create: 6
Starting process id: 5
Starting process id: 1
Starting process id: 3
Starting process id: 2
Starting process id: 4
Prime Number Associated with this thread 2 is: 7
Prime Number Associated with this thread 4 is: 11
Completed process id: 4
Prime Number Associated with this thread 1 is: 3
Completed process id: 1
Prime Number Associated with this thread 5 is: 5
Completed process id: 5
Prime Number Associated with this thread 3 is: 2
Starting process id: 6
Completed process id: 2
Prime Number Associated with this thread 6 is: 13
Completed process id: 6
Completed process id: 3
****This is where the project ends*****
After clarifying the problem:
a) getting zero as a result - well in fact it is not the case, I have actually run the code this time :) It returns total randomish result as expected, depending on the number of threads created. (Note that you use threads, not processes.)
The reason for randomish result is that each thread instance starts from the value set by other thread instances. As execution order is not deterministic, the output is not deterministic either.
b) not getting prime numbers generated one after the another - this is because the calculation starts with multiple threads at the same time, and those threads work in parallel (that's what the pooled executor does).
To force all your tasks running sequentially, use a newSingleThreadExecutor.
// final ExecutorService executor = Executors.newFixedThreadPool(n); // this uses a pool
final ExecutorService executor = Executors.newSingleThreadExecutor(); // this is sequential
public static void main(String[] args) throws InterruptedException {
System.out.println("****This is where the project starts*****");
final Scanner reader = new Scanner(System.in);
System.out.print("Enter number of processes you want to create: ");
final int n = reader.nextInt();
// final ExecutorService executor = Executors.newFixedThreadPool(n); // this uses a pool
final ExecutorService executor = Executors.newSingleThreadExecutor(); // this uses a single thread
for(int i=1;i<=n; i++) {
executor.submit(new Processor(i));
}
executor.awaitTermination(10, TimeUnit.MINUTES);
System.out.println("****This is where the project ends*****");
}
The expected output is produced as:
****This is where the project starts***** Enter number of processes you want to create: 10 Starting process id: 1 Prime Number Associated
with this thread is: 2 Completed process id: 1 Starting process id: 2
Prime Number Associated with this thread is: 3 Completed process id: 2
Starting process id: 3 Prime Number Associated with this thread is: 5
Completed process id: 3 Starting process id: 4 Prime Number Associated
with this thread is: 7 Completed process id: 4 Starting process id: 5
Prime Number Associated with this thread is: 11 Completed process id:
5 Starting process id: 6 Prime Number Associated with this thread is:
13 Completed process id: 6 Starting process id: 7 Prime Number
Associated with this thread is: 17 Completed process id: 7 Starting
process id: 8 Prime Number Associated with this thread is: 19
Completed process id: 8 Starting process id: 9 Prime Number Associated
with this thread is: 23 Completed process id: 9 Starting process id:
10 Prime Number Associated with this thread is: 29 Completed process
id: 10
Note that as the execution is actually serialized, you will have no performance gain by using an executor (or separate execution threads) here.
The best problems which can benefit from parallel execution are problems where the inputs can be splitted, then processed by multiple threads in parallel, and finally composed back again. For example, converting a bitmap picture to black-and-white is a good problem for parallel execution, as the bitmap can be sliced into 8 pieces, and these pieces fed to 8 threads running in parallel. Finally once all threads are completed, the code can assembly the output to one picture, and benefit from the 8x faster execution.
When looking at the output, you can see that all 4 threads start before any computation. The prime number is calculated right after a thread starts, so it's very likely that all threads start with the same starting prime number (0), so finishes with the same ending number (2). As a result, the output you got makes sense.
The biggest problem with your code is that you execute computations in parallel, but expect the results in sequence. To achieve an output as you want, you can wrap the Utils.generateNextPrime(currentPrimeNo) method invocation in a synchronized block. This will make sure only one thread can take action on the prime value at a time.
Update 1: This is the output I got when running your code:
****This is where the project starts*****
Enter number of processes you want to create: 4
Starting process id: 2
Prime Number Associated with this thread is: 2
Completed process id: 2
Starting process id: 1
Prime Number Associated with this thread is: 3
Completed process id: 1
Starting process id: 4
Prime Number Associated with this thread is: 5
Completed process id: 4
Starting process id: 3
Prime Number Associated with this thread is: 7
Completed process id: 3
****This is where the project ends*****
Update 2: You can also change your Processor class like the following, without synchronizing the generateNextPrime method:
public class Processor implements Runnable {
private static Object lock = new Object();
private int id;
private static volatile int currentPrimeNo = 0;
public Processor(int id) {
this.id = id;
}
#Override
public void run() {
System.out.println("Starting process id: " + id);
synchronized (lock) {
currentPrimeNo = generateNextPrime(currentPrimeNo);
}
System.out.println("Prime Number Associated with this thread is: " + currentPrimeNo);
System.out.println("Completed process id: " + id);
}
}
I tried to compile the example from Thinking in Java by Bruce Eckel:
import java.util.concurrent.*;
public class SimplePriorities implements Runnable {
private int countDown = 5;
private volatile double d; // No optimization
private int priority;
public SimplePriorities(int priority) {
this.priority = priority;
}
public String toString() {
return Thread.currentThread() + ": " + countDown;
}
public void run() {
Thread.currentThread().setPriority(priority);
while(true) {
// An expensive, interruptable operation:
for(int i = 1; i < 100000; i++) {
d += (Math.PI + Math.E) / (double)i;
if(i % 1000 == 0)
Thread.yield();
}
System.out.println(this);
if(--countDown == 0) return;
}
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i < 5; i++)
exec.execute(
new SimplePriorities(Thread.MIN_PRIORITY));
exec.execute(
new SimplePriorities(Thread.MAX_PRIORITY));
exec.shutdown();
}
}
According to the book, the output has to look like:
Thread[pool-1-thread-6,10,main]: 5
Thread[pool-1-thread-6,10,main]: 4
Thread[pool-1-thread-6,10,main]: 3
Thread[pool-1-thread-6,10,main]: 2
Thread[pool-1-thread-6,10,main]: 1
Thread[pool-1-thread-3,1,main]: 5
Thread[pool-1-thread-2,1,main]: 5
Thread[pool-1-thread-1,1,main]: 5
...
But in my case 6th thread doesn't execute its task at first and threads are disordered. Could you please explain me what's wrong? I just copied the source and didn't add any strings of code.
The code is working fine and with the output from the book.
Your IDE probably has console window with the scroll bar - just scroll it up and see the 6th thread first doing its job.
However, the results may differ depending on OS / JVM version. This code runs as expected for me on Windows 10 / JVM 8
There are two issues here:
If two threads with the same priority want to write output, which one goes first?
The order of threads (with the same priority) is undefined, therefore the order of output is undefined. It is likely that a single thread is allowed to write several outputs in a row (because that's how most thread schedulers work), but it could also be completely random, or anything in between.
How many threads will a cached thread pool create?
That depends on your system. If you run on a dual-core system, creating more than 4 threads is pointless, because there hardly won't be any CPU available to execute those threads. In this scenario further tasks will be queued and executed only after earlier tasks are completed.
Hint: there is also a fixed-size thread pool, experimenting with that should change the output.
In summary there is nothing wrong with your code, it is just wrong to assume that threads are executed in any order. It is even technically possible (although very unlikely), that the first task is already completed before the last task is even started. If your book says that the above order is "correct" then the book is simply wrong. On an average system that might be the most likely output, but - as above - with threads there is never any order, unless you enforce it.
One way to enforce it are thread priorities - higher priorities will get their work done first - you can find other concepts in the concurrent package.
I just started working with notify, synchronized and wait, and it almost works, but only when I let the second Thread sleep() for 1 ms. You can see my console output at the end.
My main:
public static void main(String[] args) {
InfoPaket paket = new InfoPaket();
TestThread testThread = new TestThread(paket);
TestThread2 testThread2 = new TestThread2(paket);
}
My "Lock" Class
public class InfoPaket {
String info;
char infoDataSign;
boolean newInfo = false;
public synchronized boolean isNew(){
if (!newInfo){
try {
System.out.println("waiting");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return newInfo;
}
public synchronized String getInfo() {
newInfo = false;
return info;
}
public synchronized void setInfo(String info) {this.info = info;
newInfo = true;
notify();
}
My two test Thread
1.
public class TestThread implements Runnable {
InfoPaket info;
int i = 0;
public TestThread(InfoPaket info) {
this.info = info;
new Thread(this,"TestThread").start();
}
public void run() {
while(true){
i++;
getInfo();
}
}
void getInfo(){
info.isNew();
System.out.println("he got it... " + info.getInfo() + " " + i);
}
2.
public class TestThread2 implements Runnable{
InfoPaket info;
Thread t;
int i = 0;
public TestThread2(InfoPaket info) {
this.info = info;
t = new Thread(this,"TestThread");
t.start();
}
public void run() {
while(i < 500000){
i++;
setInfo();
}
}
void setInfo(){
info.setInfo("lelaoao");
System.out.println("here " + i);
try {
t.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Here my results which are very clear and nice (except for the start):
waiting
he got it... lelaoao 1
waiting
here 1
here 2
he got it... lelaoao 2
waiting
here 3
he got it... lelaoao 3
waiting
here 4
he got it... lelaoao 4
waiting
here 5
he got it... lelaoao 5
waiting
here 6
he got it... lelaoao 6
And so on..
But putting the 2. thread everytime asleep slows down the program,
but without it I get something strange that I can't explain to myself:
waiting
here 1
he got it... lelaoao 1
he got it... lelaoao 2
waiting
here 2
here 3
he got it... lelaoao 3
he got it... lelaoao 4
waiting
here 4
here 5
here 6
here 7
here 8
here 9
here 10
he got it... lelaoao 5
he got it... lelaoao 6
waiting
You code is working as expected (as coded), except - 1) You have some bad code 2) You may have misunderstood the concept.
Let me first start by saying what your code is doing:
You have a InfoPaket which is shared among your 2 thread and hold info about packet, and keeps track whether new info is received or not.
Then your have TestThread which will check if new info is received or not, if new info is not recieved then it will wait and once new info is received then you will print the info (which is always "lelaoao") along with your loop counter, like this he got it... lelaoao 23
Then your have TestThread2 which will set the info and notify the waiting thread and then print the loop counter of this thread like this - "here " + i.
Now, most important thing for your understand is that thread scheduling is unexpected and depends on underlying OS thread scheduling mechanism as well as JVM implementation, so you cannot expect that if thread 2 has set info then then certainly thread 1 will execute, you can try to enforce it putting Thread.sleep(1) or Thread.yeild(), please note that Thread.yeild() is not portable and it is good that you are not using it and should not be use it, instead of it you should use Thread.sleep(1)
Now let come to bad code and some important concepts:
Bad code
The most wrong thing you were doing is you were starting a new thread from the constructor, don't ever try to start a new thread from the constructor because it will cause your reference to leak even before your constructor has completed. Read this excellent article.
You don't need a reference of current thread in TestThread2 because you can directly do Thread.sleep(1); which will cause current thread to sleep.
You were printing System.out.println("he got it... " + info + " " + i); and System.out.println("here " + i); from your main thread, however you should print these from synchronized block to ensure that there is no interleaving, because in absence of synchronization interleaving could occur and you could see he got it... lelaoao 3 before here 3 which is logically wrong.
Now, below is the fixed code which will consistent produce correct result (considering your are giving thread 1 chance to run once thread 2 has set info), output is also placed in the end.
InfoPaket.java
public class InfoPaket {
String info;
char infoDataSign;
boolean newInfo = false;
public synchronized boolean isNew() {
if (!newInfo) {
try {
System.out.println("waiting");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return newInfo;
}
public synchronized void getInfo(int i) {
newInfo = false;
System.out.println("he got it... " + info + " " + i);
}
public synchronized void setInfo(String info, int i) {
this.info = info;
newInfo = true;
System.out.println("here " + i);
notify();
}
public static void main(String[] args) {
InfoPaket paket = new InfoPaket();
TestThread testThread = new TestThread(paket);
TestThread2 testThread2 = new TestThread2(paket);
new Thread(testThread, "testThread").start();
new Thread(testThread2, "testThread2").start();
}
}
TestThread.java
public class TestThread implements Runnable {
InfoPaket info;
int i = 0;
public TestThread(InfoPaket info) {
this.info = info;
}
public void run() {
while (true) {
i++;
getInfo(i);
}
}
void getInfo(int i2){
info.isNew();
info.getInfo(i2);
}
}
TestThread2.java
public class TestThread2 implements Runnable {
InfoPaket info;
int i = 0;
public TestThread2(InfoPaket info) {
this.info = info;
}
public void run() {
while (i < 500000) {
i++;
setInfo(i);
}
}
void setInfo(int i2) {
info.setInfo("lelaoao", i2);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output:
waiting
here 1
he got it... lelaoao 1
waiting
here 2
he got it... lelaoao 2
waiting
here 3
he got it... lelaoao 3
waiting
here 4
he got it... lelaoao 4
waiting
here 5
he got it... lelaoao 5
waiting
here 6
he got it... lelaoao 6
waiting
here 7
he got it... lelaoao 7
waiting
here 8
he got it... lelaoao 8
waiting
here 9
he got it... lelaoao 9
waiting
here 10
he got it... lelaoao 10
waiting
here 11
he got it... lelaoao 11
waiting
here 12
he got it... lelaoao 12
waiting
here 13
he got it... lelaoao 13
waiting
here 14
he got it... lelaoao 14
waiting
here 15
he got it... lelaoao 15
waiting
here 16
he got it... lelaoao 16
waiting
here 17
he got it... lelaoao 17
waiting
here 18
he got it... lelaoao 18
waiting
here 19
he got it... lelaoao 19
waiting
here 20
he got it... lelaoao 20
waiting
here 21
he got it... lelaoao 21
waiting
here 22
he got it... lelaoao 22
waiting
here 23
he got it... lelaoao 23
waiting
here 24
he got it... lelaoao 24
waiting
here 25
he got it... lelaoao 25
waiting
here 26
he got it... lelaoao 26
waiting
here 27
he got it... lelaoao 27
waiting
here 28
he got it... lelaoao 28
waiting
here 29
he got it... lelaoao 29
waiting
here 30
he got it... lelaoao 30
waiting
here 31
he got it... lelaoao 31
Important concepts to be clear about
I think you might be missing some concept so you are thinking output to be crazy.
Once you have set the info using thread 2 there is no guarantee that thread 1 will run because thread scheduling is unexpected and depends on underlying OS thread scheduling mechanism as well as JVM implementation, I have highlighted more point about this in the start with Thread.yield() and Thread.sleep(). With that note, if you don't use Thread.sleep(1) then you just can't expect output to be consistent, as I have shown below.
When you do Thread.sleep then it doesn't release the lock, if that thread is acquiring some lock.
Once you do notify(); then you can't expect the waiting thread to be "runnable" immediately and the thread which is acquiring the lock will not release immediately release the lock as soon as notify(); is called, lock will be released only once that synchronized block/method is finished.
If you don't do Thread.sleep(1) in your 2nd thread then you can't expect the consistent output, and reasons I have explained above.
OP's comment:
Do you know any a more efficent way of transmitting data from on
thread to an other one?
Either you have "shared memory" or "message passing"; shared memory is what we are doing in this case, and if you want to go for message passing then you can go for Java API like blocking queue (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html) implementation, but that's becomes all together different story.
While running each thread why does the countdown.getCount() always print '3' even after the previous thread has already called countdown.countDown() and reduced the Latch Count by 1?
I am kind of worndering how Java knows that the Latch Count has reached 0, so that it can release all the 3 threads.
import java.util.concurrent.CountDownLatch;
class b {
static final CountDownLatch countdown = new CountDownLatch(3);
public static void main(String[] args) {
for (int i = 0; i < 3; ++i) {
Thread t = new Thread() {
public void run() {
System.out.printf("Starting on %d other threads.\n",
countdown.getCount());
countdown.countDown();
System.out.printf("new on %d other threads.\n",
countdown.getCount());
try {
countdown.await(); // waits until everyone reaches this
// point
// System.out.println("Go again : "
// +countdown.getCount());
} catch (Exception e) {
}
}
};
t.start();
}
System.out.println("Go");
}
}
you are starting 3 threads in parallel. depending on how fast they start, they could all print "3" before any of the threads manages to call countDown() (at least for the "Starting on..." line). the "new on ..." line, however, should print out some range of numbers between 2 and 0.
It's absolutely possible that all three threads print "Starting on 3.." as the threads run in parallel, and the count doesn't change until a thread executed countDown(). To really understand what's going on, I suggest you prepend System.nanoTime() and thread name before your print statements as below:
...
Thread t = new Thread("Thread-" + i) {
...
System.out.printf("%d> %s: Starting on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount());
countdown.countDown();
System.out.printf("%d> %s: new on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount());
Sometimes you'd get an output like below which may give you the impression that Thread-2 is disregarding Thread-1's call to countDown:
1407489646569321000> Thread-0: Starting on 3 other threads.
1407489646569324000> Thread-1: Starting on 3 other threads.
1407489646602463000> Thread-1: new on 1 other threads.
1407489646569513000> Thread-2: Starting on 3 other threads.
1407489646602107000> Thread-0: new on 2 other threads.
1407489646603275000> Thread-2: new on 0 other threads.
However, that is not the case, and we can verify the correct order of operations by looking at the timestamp. The mixup in the output is due to inherent unpredictability in thread scheduling, depending on which thread gets the cpu splice.
Having said that, they may not always print 3, depending on thread scheduling or delays. As an example, try putting a Thread.sleep(..) as shown below:
public static void main(String[] args) throws Exception {
for (int i = 0; i < 3; ++i) {
Thread t = new Thread() {
public void run() {
/* As before */
}
};
t.start();
Thread.sleep(100); // Artificial Delay
}
}
Now you should see different results like below:!
1407490223575404000> Thread-0: Starting on 3 other threads.
1407490223607879000> Thread-0: new on 2 other threads.
1407490223676233000> Thread-1: Starting on 2 other threads.
1407490223676818000> Thread-1: new on 1 other threads.
1407490223777623000> Thread-2: Starting on 1 other threads.
1407490223778221000> Thread-2: new on 0 other threads.
Internally, the CountDownLatch maintains a first in, first out wait Queue (See. AbstractQueuedSynchronizer). The value of the count is synchronized, and the waiting threads are only released when the count becomes 0 or someother thread interrupts the waiting thread. This is the mechanism used by the latch to keep track of when all the threads have arrived at the latch.
If you're interested in understanding the latch in the context of testing, checkout http://razshahriar.com/2014/08/testing-asynchronous-code-in-java-with-countdownlatch/
Hope this helps clarify your investigation of the Program behaviour.