I recently came across this code snippet
class Counter2 implements Runnable{
private int value = 0;
private Integer lock = 0;
public void increment(){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
value++;
}
public void decrement(){
value--;
}
public int getValue() {
return value;
}
@Override
public void run() {
synchronized(lock) {
this.increment();
System.out.println(String.format("%s incremented value, value = %s", Thread.currentThread().getName(), this.value));
this.decrement();
System.out.println(String.format("%s decremented value, value = %s", Thread.currentThread().getName(), this.value));
}
}
}
public class Part8_synchronized_keyword_1 {
public static void main(String[] args) {
Counter2 counter = new Counter2();
new Thread(counter,"Thread1").start();
new Thread(counter,"Thread2").start();
new Thread(counter,"Thread3").start();
new Thread(counter,"Thread4").start();
Counter2 counterB = new Counter2();
new Thread(counterB, "ThreadB").start();
}
}
I get the output as follows
Thread1 incremented value, value = 1
Thread1 decremented value, value = 0
ThreadB incremented value, value = 1
ThreadB decremented value, value = 0
Thread4 incremented value, value = 1
Thread4 decremented value, value = 0
Thread3 incremented value, value = 1
Thread3 decremented value, value = 0
Thread2 incremented value, value = 1
Thread2 decremented value, value = 0
Why is it that it seems that threadB is competing with thread1...4 for the same lock?. Because from my understanding the lock object will be different for counterB and counter
Your assumption that counter
and counterB
use different locks is wrong.
Why: because you declared your lock as
private Integer lock = 0;
and the JVM caches Integer
objects for all values from -128 to 127.
Declare your lock as
private Object lock = new Object();
and only then will counter
and counterB
use different locks!
Note the important distinction here between object references and the referenced objects:
Both counter
and counterB
have a field lock
, but these fields are not objects, they are merely references to some object.
For
private Integer lock = 0;
that referenced "some object" is the same for counter
and counterB
(because the Java Language Specification requires this for boxing of int
values in the range -128 to 127) and synchronization happens on the object, not on the reference.
Excerpt from the Java Language Specification, Boxing Conversion:
If the value
p
being boxed is the result of evaluating a constant expression (§15.29) of typeboolean
,byte
,char
,short
,int
, orlong
, and the result istrue
,false
, a character in the range'\u0000'
to'\u007f'
inclusive, or an integer in the range-128
to127
inclusive, then leta
andb
be the results of any two boxing conversions ofp
. It is always the case thata == b
.