Here's my code:
private int count = 0;
public synchronized void increment() {
count++;
}
public void doWork() throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
increment();
System.out.println(count+" "+Thread.currentThread().getName());
}}});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
increment();
System.out.println(count+" "+Thread.currentThread().getName());
}}});
t1.start();
t2.start();
}
Here's my output:
2 Thread-1
2 Thread-0
3 Thread-1
5 Thread-1
6 Thread-1
4 Thread-0
8 Thread-0
9 Thread-0
7 Thread-1
10 Thread-0
My understanding is that increment
is synchronized
. So, it should first increment
one number and then release the lock
and then give the lock
to the thread t1
or t2
. So, it should increment
one number at a time, right?
But why is my code incrementing
two or three numbers at a time? Am I doing something wrong (I'm a newbie)?
While
count++;
indeed is synchronizedSystem.out.println(count+" "+Thread.currentThread().getName());
is not, but it access tocount
variable.Even if you synchronize access, it won't help you because next scenario will be still possible:
2
2
To fix this issue you need to increment and print in same synchronized section. For example you can put
System.out.println(count+" "+Thread.currentThread().getName());
intoincrement
method.One alternative solution without using
synchronized
.Since your use case is simple ( just incrimenting the counter and print the value, AtomicInteger is better choice.
output:
Refer to @fabian answer for why these numbers are nor not printed in sequence.
If you expect the sequence in series of numbers in ascending order from 1-10, Threads are not required.
The
increment
method can be run on the other thread after theincrement
method returns, but beforecount
is retrieved for the concatenationYou could e.g. fix this by modifying and retrieving
count
in one synchronized block:Or use the class in the standard library specifically designed for this purpose:
Of course this does not necessarily lead the numbers 1 to 10 being printed in order, just that no number is retrieved more than once. The following output could happen:
What actually happens is that your Threads are snapshotting (maybe a another word is better here) the current value of the variable
count
and display it. You can think of it like there is a blue bucket with the number zero and bothThreads
are getting the same bucket in the same color and number. They now work individually on those buckets.If you want them to work on the same bucket, you have to make them atomic e.g. with
AtomicInteger
orvolatile
or any other tool from the java concurrent package.Solution 1: Given by fabian. To give a single function
incrementAndGet()
.Solution 2: A
synchronized
block instead ofsynchronized
method (if possible):Complete code would be like: