Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a thread change java locked object data if it is not requesting the lock itself?

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
like image 740
Oliver Scott Avatar asked Jan 22 '26 16:01

Oliver Scott


1 Answers

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.

like image 60
RealSkeptic Avatar answered Jan 25 '26 05:01

RealSkeptic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!