Reputation: 18614
I want to measure how long it takes for the 2 threads to count till 1000. How can I make a benchmark test of the following code?
public class Main extends Thread {
public static int number = 0;
public static void main(String[] args) {
Thread t1 = new Main();
Thread t2 = new Main();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
}
public synchronized void increment() {
number++;
}
public synchronized int getNumber() {
return number;
}
}
And why am I still getting the following result (extract) even though I use the synchronized
keyword?
Thread-0 9
Thread-0 11
Thread-0 12
Thread-0 13
Thread-1 10
Upvotes: 2
Views: 1105
Reputation: 121790
why am I still getting the following result (extract) even though I use the synchronized keyword?
You synchronize access to the number
variable, however the increment and get are synchronized separately, and this does not make your println()
atomic either. This sequence is perfectly possible:
0 -> inc
1 -> inc
0 -> getnumber
1 -> getnumber
1 -> print
0 -> print
First, if you want to solve the "increment and get" problem, you can use an AtomicInteger
:
private static final AtomicInteger count = new AtomicInteger(0);
// ...
@Override
public void run()
{
final String me = getName();
for (int i = 0; i < 1000; i++)
System.out.println(me + ": " + count.incrementAndGet());
}
However, even this will not guarantee printing order. With the code above, this scenario is still possible:
0 -> inc
0 -> getnumber
1 -> inc
1 -> getnumber
1 -> print
0 -> print
To solve this problem, you need to use, for instance, a ReentrantLock
:
private static final Lock lock = new ReentrantLock();
private static int count;
// ...
@Override
public void run()
{
final String me = getName;
for (int i = 0; i < 1000; i++) {
// ALWAYS lock() in front of a try block and unlock() in finally
lock.lock();
try {
count++;
System.out.println(me + ": " + count);
finally {
lock.unlock();
}
}
}
Upvotes: 1
Reputation: 24895
You are not synchronizing this:
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
So, a thread can execute increment()
, wait for the next thread, and after that keep with getValue()
(thus getting your results). Given how fast is adding a value, changing a thread gives the other time for several iterations.
Do public static final String LOCK = "lock";
synchronized(LOCK) {
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
}
you do not need the synchronize
for the methods (as I explain in my comment).
Upvotes: 1
Reputation: 2683
You are not synchronized. The synchronized
keyword is an equivalent to synchonize (this) {}
but you are increasing a static
number which is not contained within your object. You actually have 2 objects/threads and both of them synchronize with themself, not with each other.
Either make you property volatile
and don't synchronize at all or use a lock Object like this:
public static int number = 0;
public static final Object lock = new Object();
public void increment() {
synchronized (lock) {
number++;
}
}
public int getNumber() {
synchronized (lock) {
return number;
}
}
Upvotes: 1
Reputation: 15278
Output is not synchronized. The scenario is:
10
.10
.Upvotes: 1