I have a thread class which implements runnable and an int counter as instance variable. Two synchronized methods add and sub. When I run my test class somehow it is printing wrong results once in couple of times. As far as I understand when a method is synchronized, entire object will be locked for accessing by other threads, with this logic every time we should get same results right? Some how that is not the case. Am I missing something?
My machine is Windows 7, 64 bit.
public class ThreadClass implements Runnable {
int counter = 0;
@Override
public void run() {
add();
sub();
}
public synchronized void add() {
System.out.println("ADD counter" + (counter = counter + 1));
}
public synchronized void sub() {
System.out.println("SUB counter" + (counter = counter - 1));
}
}
Testclass
public class ThreadTest {
public static void main(String args[]) {
ThreadClass tc = new ThreadClass();
Thread tc0 = new Thread(tc);
tc0.start();
tc0.setPriority(Thread.MAX_PRIORITY);
Thread tc1 = new Thread(tc);
tc1.start();
tc1.setPriority(Thread.NORM_PRIORITY);
Thread tc2 = new Thread(tc);
tc2.start();
tc2.setPriority(Thread.MIN_PRIORITY);
}
}
Results
ADD counter1
ADD counter2
SUB counter1
SUB counter0
ADD counter1
SUB counter0
Note: You may need to do couple of runs to produce this inconsistency.
Synchronization will indeed mean that all threads will block waiting to acquire a lock before they can enter the synchronized block. Only one thread can ever have the lock on the object, so only one thread can be in the
add()orsub()methods.However, this does not imply anything else about the ordering of threads. You’re starting three threads – the only guarantee is that they won’t stomp on each other by running the
addorsubmethods at once. Thread 1 can calladd(), then thread 3 can calladd(), then thread 2 can calladd(), then they can all callsub(). Or they could all calladd()and thensub()each. Or any mixture – the only requirement being that each thread callsadd()before it callssub()and that no two threads will ever calladd()orsub()while another thread is in that method.Aside: it can be, in some cases, bad form to synchronize on
this, as it’s public – it’s often preferred to use an internal privateObjectto lock on so that no other callers can take your lock and violate any locking strategies you have designed.