Reputation: 595
class Call {
int count;
public void increment() {
for (int i = 0; i < 1000; i++)
count++;
}
}
class Caller implements Runnable {
Call c;
public Caller(Call c) {
this.c = c;
}
@Override
public void run() {
// TODO Auto-generated method stub
c.increment();
}
}
class Calling implements Runnable {
Call c;
public Calling(Call c) {
this.c = c;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (c) {
c.increment();
}
}
}
public class SynchronizedBlock {
public static void main(String[] args) throws InterruptedException {
Call call = new Call();
Calling calling = new Calling(call);
Caller caller = new Caller(call);
Thread t1 = new Thread(caller);
Thread t2 = new Thread(calling);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("caller:" + caller.c.count);
}
}
Here have made increment method synchronized in 1 class and in other class i havent made it as synchronized. When i run the above code , it sometimes gives value of count less than 2000 .
As per my understanding, Since Calling class's object has already locked the object, so there is no need to synchronize in Caller class increment method.
Could you please help me in understanding the logic here.
Upvotes: 0
Views: 70
Reputation: 3355
synchronized
keyword in java means that lock will be acquired before entering the block and released after exit.
Since t2 acquires/releases the lock and t1 doesn't, there is effectively no synchronization going on. t1 just goes in the block whenever the CPU time is assigned to it.
t2 also always goes in the block without waiting because the lock is never acquired by t1.
--
If you synchronize the increment
method your program will work correctly:
class Call {
int count;
public synchronized void increment() {
for (int i = 0; i < 1000; i++)
count++;
}
}
After this change you can remove the synchronized block from t2.
Upvotes: 1
Reputation: 23684
What's probably happening when you get the correct value of 2000
, happens between the lines:
t1.start();
t2.start();
This is because the execution of public void increment();
is finishing in a single quantum, before the t2.start()
line is even executed. A Thread Quantum is the time that the thread runs before a different thread can run on the processors core.
The first thread doesn't lock the object, and occasionally a single quantum will not encompass the entire execution of increment()
, which leaves time for thread 2 to begin executing and working on the same object data. This will result in 2 copies of the variable count
existing at the same time, competing for the same memory.
Try increasing the amount of increments for (int i = 0; i < 1000; i++)
to some number like for (int i = 0; i < 10000000; i++)
. You will most likely see the application begin to fail more often.
Upvotes: 0
Reputation: 44808
Since Calling class's object has already locked the object, so there is no need to synchronize in Caller class increment method.
Your understanding is incorrect. In order for parallel actions on a variable to be deterministic, you must have some sort of synchronization in place on every access/modification to that variable**.
You need to synchronize
in Caller
as well.
**: This is a necessary but insufficient condition to guarantee determinism.
Upvotes: 1