Oracle's tutorial Intrinsic Locks and Synchronization says:
Intrinsic[Monitor] locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state
I assumed no value in an object could be manipulated by two threads at once, should one thread be executing a 'synchronized' method.
As such, I was surprised (although relieved for the purposes of what I am looking to do) when the following code had the following output. I wasn't entirely sure what to expect, however I figured an error or some point might occur.
From what I can understand, 'synchronized' merely acts to restrict access to an object, if another thread is requesting the monitor state for that object -- but not if that other thread is altering a one off value. Is this correct?
public class HelloWorld implements Runnable{
Thread t1;
Thread t2;
int val1 = 0;
int val2 = 0;
public static void main(String[] args) {
HelloWorld h1 = new HelloWorld();
h1.t1 = new Thread(h1);
h1.t2 = new Thread(h1);
h1.t1.start();
h1.t2.start();
}
@Override
public void run() {
System.out.println("STARTED");
System.gc();
Thread currentThread = Thread.currentThread();
if (currentThread == this.t1) {
this.locker(); //This is a synchronized method, incrementing val1
}
if (currentThread == this.t2) {
this.adder(); //This is a non-synchronized method, incrementing val2
}
}
private synchronized void locker() {
for(int i = 0; i < 3; i++){
val1++;
System.out.println("LOCKER: " + this.val1);
}
}
private void adder() {
while(this.val2 < 3) {
this.val2++;
System.out.println("ADDER: " + this.val2);
}
synchronized(this) {
//Synchronize for final output
System.out.println("FINAL");
System.out.println(val1);
System.out.println(val2);
}
}
}
STARTED
STARTED
ADDER: 1
LOCKER: 1
LOCKER: 2
ADDER: 2
LOCKER: 3
ADDER: 3
FINAL
3
3
The phrasing "enforcing exclusive access to an object's state" may be misleading. Synchronized code can be used to achieve exclusive access to an object's state, but (a) it doesn't enforce that, and (b) the protected state is not necessarily the state of the object that is being locked. This is demonstrated in the example later on in that tutorial, where the two objects lock1 and lock2 are used to protect the fields c1 and c2 which are not part of their own state.
What synchronized enforces is exclusive access to code - any code that is within a synchronized block on the same monitor can be ran only by the thread that owns that monitor. This can be used to ensure exclusive access to the state - but only if you write your code properly (i.e. you place all access to that state within synchronized blocks).
Nothing prevents you from writing a program that accesses a field from unprotected code, and in that case, exclusive access will not be enforced.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With