Im trying to understand threads.
I wrote simple program.
public class Main {
static int counter = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter);
}
}
The result is always 2000, but I do not know understand why. Any of the run methods are not synchronized so why it is giving me always the same result.
If I write:
t1.start();
t1.join();
System.out.println(counter);
t2.start();
System.out.println(counter);
then I got result: 1000,1000. Why it is always equals to 1000?
Your loops are so short that t1 finishes before t2 gets going. Try 100,000 instead. Lack of synchronization does not guarantee you will have concurrency issues but correctly incorporating synchronization will prevent them.
The result is always 2000, but I do not know understand why.
because you were lucky enough to not have any race condition between the two threads. Just because a race condition can happen doesn't mean that it's guaranteed to happen.
Why it is always equals to 1000?
Because the second thread has not executed yet when you print the counter for the second time. Or because it has executed, but since there is no visibilty guarantee due to the lack of synchronization, the main thread can still see the latest value.
Related
This question already has answers here:
Java volatile keyword not working as expected
(6 answers)
Closed 14 days ago.
Created 2 threads and called the join() method on them. I was expecting the threads would run sequentially and give the desired result, but I am getting some random values in the result.
public class TestJoinMethod {
volatile private int count =0;
public static void main(String[] args) {
TestJoinMethod testJoinMethod = new TestJoinMethod();
testJoinMethod.execute();
}
public void execute() {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i<10000; i++) {
count++;
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i<10000; i++) {
count++;
}
}
});
t1.start();
t2.start();
try {
t1.join();
System.out.println(count);
t2.join();
System.out.println(count);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Using the above code to get the value of count variable. As per my understanding the join() method waits for the thread execution to be completed before the control of the calling thread goes to next statement. Expected result : sysout statement should print 10000 , 200000 respectively. However, the result is giving some random values : 14125 , 14125 or 16911, 16911.
Not able to understand why is this happening here, went through some tutorials also, but couldn't understand the exact issue here.
Appreciate your help here.
So let's think about the sequence that happens here. This part:
t1.start();
t2.start();
Starts the two threads running, concurrently with each other. We haven't executed a join() yet, just started the two threads, so they're both running.
try {
t1.join();
System.out.println(count);
Then we get to this join(). Both t1 and t2 have been running for a while at this point. Finally, t1 finishes and then we print out count. But t2 has also been running, so we expect count to have been incremented more than it would have been by t1 alone.
Then we get to this:
t2.join();
System.out.println(count);
This does pretty much the same thing: wait for t2 to finish, then print out count again.
It's essentially impossible to predict how much of the execution of t1 and t2 may overlap with each other though. Maybe a lot, but maybe almost none at all.
Worse, you haven't done anything to protect access to count, you're getting a data race. The result is, in a word, garbage.
To get the result you're apparently looking for, you'd have prevent concurrent access of your threads though (in other words, render the use of threads utterly useless). The obvious way to do that would be something like:
t1.start();
t1.join();
System.out.println(count);
t2.start();
t2.join();
System.out.println(count);
This should produce the result you desire--but it's equivalent to just running all the code in one thread, so there's no real point to any of it.
The compiler already is warning you that
Non-atomic operation on volatile field 'count'
The threads can randomly read the same value and update it at the same time, which will result in the same number. For example:
Thread 1 reads count = 0
Thread 2 reads count = 0
Thread 1 does 0+1
Thread 1 updates count = 1
Thread 2 does 0+1
Thread 2 updates count = 1
This can be solved synchronizing the access to the count variable, for example using AtomicInteger:
private final AtomicInteger count = new AtomicInteger(0);
count.getAndIncrement();
Also note that the final result will be 20000 for both threads, you're incrementing the same counter.
I'm well aware that this might be considered a duplicate, however I ran through many answers considering my problem here I can't come up with a solution.
I synchronized my runnable with an object shared by multiple threads and explicitly synchronized the method I am using inside, but the outcome of the program is always 3000.
I tried locking the Counter class but it won't change a thing.
Could anyone explain me why none of my actions work in this particular example?
public static void zad3() {
var counter = new Counter();
var toRun = new Runnable() {
#Override
public void run() {
synchronized (counter) {
for (var i = 0; i < 1000; i++) {
counter.add(1);
}
}
}
};
var t1 = new Thread(toRun);
var t2 = new Thread(toRun);
var t3 = new Thread(toRun);
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("counter = " + counter.getCount());
}
public class Counter {
protected long count_ = 0;
public synchronized void add(long value) {
count_ += value;
}
public long getCount() {
return count_;
}
}
edit:
As suggested the problem was in the loop being constantly ran a 1000 times by each of the threads.
My solution:
var toRun = new Runnable() {
#Override
public void run() {
synchronized (counter) {
for (var i = counter.getCount(); i < 1000; i++) {
counter.add(1);
}
}
}
};
Well you have synchronized the complete for loop around the "counter" variable which means that each thread will run tthe block once. 3 X 1000 = 3000
this block will be executed once per thread
for (var i = 0; i < 1000; i++) {
counter.add(1);
}
UPDATE: judging from your comments that you want interrupt on 1000 example code can be:
t1.start();
t2.start();
t3.start();
while(counter.getValue()<1000) {
Thread.sleep(20)
}
Annother suggestion:
public class Incremetor extends Runnable {
Counter counter;
public Incremetor(Counter counter) {
this.counter = counter;
}
public void run() {
counter.increment();
}
}
ExecutorService executorService = Executors.newFixedThreadPool(8); // this mean 8 threads in total to do your runnables.
for (int i=0;i<1000;++i) {
executorService.submit(new Incrementor(counter));
}
So the problem is that you let each thread attempt 1000 increments, so you'll need something like this instead:
while (counter.getCount() < 1000) {
counter.add(1);
}
The solution you have provided may give you the correct result, but you're actually only incrementing the counter from 1 thread. When you make a synchronized block with synchronized(object) { }, all threads will attempt to get the lock for this block, but only one will. That means in your solution, that the first thread which gets the lock, will do all 1000 increments. When the thread releases the lock and lets the others get it, the work is already done. A solution that actually distributes the increments amongst the 3 threads, should therefore not synchronize the entire for-loop.
If you run the while-loop I suggested, you will get a lot closer to 1000, but it may actually be more than 1000. Remember to run your program 10 times or set up a test-function which runs it 100 times and reports back. The problem, is that from the point of reading counter.getCount(), the value may already have changed by another thread. To reliably always get 1000, you could ensure exclusive rights to both reading and writing to the counter:
while (true) {
synchronized (counter) {
if (counter.getCount() < 1000) {
counter.add(1);
} else {
break;
}
}
}
Notice that incrementing one variable like this, is slow. You're only doing 1000, but try with one billion. In fact, the 3-threaded version takes (on my PC) 1m17s, whereas a simple sequential loop takes ~1.2 seconds. You can solve this by splitting the workload amongst the threads and letting them work on a local counter with exclusive rights and then finally add the results.
The following code is shows how no race condition in thread works, but I don't get the difference between with the synchronized and without it. I thought the static variable counter will be added to 20000 anyway but it turned out that without synchronized counter would be less than 20000. Can you please explain how threads work in this case? Also, in Java, are threads are actually not running "concurrently", instead are they taking turns to run for a while?
public class NoRaceCondition implements Runnable {
private static int counter = 0;
private static Object gateKeeper = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new NoRaceCondition());
Thread t2 = new Thread(new NoRaceCondition());
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) { e.printStackTrace(); }
System.out.printf("counter = %d\n", counter);
}
public void run() {
synchronized (gateKeeper) {
for (int i = 0; i < 10000; i++) {
{
counter++;
}
}
}
}
}
You can think of count++ as 3 separate steps.
read the value of count
increment the value
override count with the new incremented value
When multiple thread execute the above steps concurrently, race conditions may occur. 1 example of race condition is
Let count = 1
Let there be 2 threads named A and B
Thread A reads the value of count and get 1
Thread B reads the value of count and get 1
Thread A increments its value and get 2
Thread B increments its value and get 2
Thread A writes the value to count
count is now 2
Thread B writes the value to count
count is now 2 again when it's expected to be 3 after 2 increments
public class TestThread2 {
static int count = 0;
public static void main(String[] args) {
Thread t = new Thread(new Runnable(){
public void run()
{
for (int i=1; i<=100000; i++) {
count++;
}
}
});
Thread t1 = new Thread(new Runnable(){
public void run()
{
for (int i=1; i<=100000; i++) {
count++;
}
}
});
t.start();
t1.start();
try{
t.join();
t1.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(count);
}
}
The above code prints various values of count such as 131938, 127518 etc. But I think it should always print 20000 as after join() is called, main thread cannot move to next statement until current thread dies. I know I'm missing a basic concept here, but I'm not able to figure it out so please help.
i++ isn't atomic. It's effectively:
int j = i;
i = j + 1;
If two threads are trying to do this at the same time, the reads and writes from different threads could interleave, meaning that the value isn't strictly incrementing in each thread.
Additionally, there is no guarantee that the increased value from one thread is visible to the other thread.
Instead of using int, use AtomicInteger, and addAndGet. AtomicInteger guarantees both the atomicity of the incrementation and the visibility of the value between threads.
static AtomicInteger count = new AtomicInteger();
// In the thread:
count.incrementAndGet();
Note that something very similar to your example is described in the Oracle Java Tutorial.
You are not synchronizing the variables. Instead of static int count, use an AtomicInteger.
Yes main thread blocks on join(). But the main thread does not write to the variable count, so it does not matter what main thread is doing. You have 2 threads, t and t1, which read and write the same variable count without any synchronization, and indeed it causes unstable results.
I am unable to understand that if my variable is both volatile and static then why threads are not reflecting the common shared value in the output
Output of last few lines is :
Thread is running
4998Thread-0
Thread is running
4999Thread-0
Thread is running
4899Thread-1
Thread is running
public class Test implements Runnable{
volatile static int i=0;
#Override
public void run() {
for(;i<5000;i++)
{ try {
Thread t = Thread.currentThread();
String name = t.getName();
// Thread.sleep(10);
System.out.println(i+name);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Thread is running");
}}
public static void main(String[] args) {
Test t=new Test();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
// t.run();
t2.start();
}
}
You can't use a compound (multi step) operation like i++ on a volatile variable.
You can have both threads retrieve the value, increase it, and write it back resulting in one lost increment (as you see in your example).
Volatile ensures that changes to the variable are visible to other threads. But it does not ensure synchronization.
From one execution of your program I get this output :
Thread is running
3474Thread-1
Thread is running
3475Thread-0
Thread is running
3477Thread-0
(.... many lines where i goes from 3478 to 4998, with Thread-0 always being the one running...)
Thread is running
4999Thread-0
Thread is running
3476Thread-1
Thread is running
This happens because threads get slices of processor time to be run and their execution can be paused and resumed at any point.
Here Thread-1 is executing line "System.out.println(i+name);" with i having a value of 3476. i+name is evaluated to "3476Thread-1" but just then the Thread-1 execution stops and instead Thread-0 gets its time slice. Thread-0 executes till finalization. And then Thread-1 gets again to execute. We have left it after i+name had been evaluated to "3476Thread-1" and before the call to println. The call is now completed and printed, hence you see "3476Thread-1" at then end. i has been increased to 5000 by Thread-0 but that does not change the result of the evaluation of i+name which was done before all those increases.
The problem is that i++ and i+name are different instructions and thread execution can be paused and resumed between them. To ensure that you get a secuential output you need to ensure than there is no interruption between i++ and i+name. That is, you need to make that set of instructions atomic.
public class Test implements Runnable{
static Object lock = new Object();
volatile static int i=0;
#Override
public void run() {
for(;;)
{
try {
Thread t = Thread.currentThread();
String name = t.getName();
synchronized( lock )
{
if ( i>=5000 )
break;
i++;
System.out.println(i+name);
}
// Thread.sleep(10);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Thread is running");
}
} }
public static void main(String[] args) {
Test t=new Test();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
// t.run();
t2.start();
}
}
In that program, if Thread-1 gets paused between i++ and i+name it will be inside the a critical section controlled by synchronized(lock). When Thread-0 gets to execute it will reach the synchronized(lock) instruction and will have to stop executing until Thread-1 resumes and gets out of that block. Because the JLS ensures that :
The synchronized statement (ยง14.19) computes a reference to an object;
it then attempts to perform a lock action on that object's monitor and
does not proceed further until the lock action has successfully
completed. After the lock action has been performed, the body of the
synchronized statement is executed. If execution of the body is ever
completed, either normally or abruptly, an unlock action is
automatically performed on that same monitor.
Here's a code snippet I learned usage of volatile keyword from:
import java.util.concurrent.TimeUnit;
public class VolatileDemo {
private volatile static boolean stop; //remove volatile keyword to see the difference
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread otherThread = new Thread(new Runnable() {
public void run() {
while (!stop)
i++;
}
});
otherThread.start();
TimeUnit.SECONDS.sleep(1);
stop = true;// main thread stops here and should stop otherThread as well
}
}
If you want to observe what volatile does, try to remove it and then follow the execution, this should be obvious after you run those two versions, but basically keyword here prevents java compiler from assuming that stop condition never changes, it will be read every time the condition gets evaluated. Neat, isn't it?
By looking at your code the problem isn't with usage of volatile keyword, the problem is that the expression i++ is not atomic. It actually is 3 step operation:
1) fetch value of i;
2) increment i;
3) save new value of i
When multi-threading comes into play, these might or might not be mixed with other thread's instructions.
So the execution might look like that as well:
1) T1: fetch i;
2) T2: fetch i;
3) T1: increment i;
4) T2: increment i;
5) T1: save i;
6) T2: save i;
If i was 0 you thought you will get 2 as the output, and here's 1 instead.
Go with synchronization, which is pretty simple when not overused and well thought.
Suggested read on synchronization
If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic.
Therefore you need to use synchronization when you modify the i value.