Java synchronization and data consistency

862 views Asked by At

Consider the following simple example:

public class Example extends Thread {
    private int internalNum;

    public void getNum() {
        if (internalNum > 1)
            System.out.println(internalNum);
        else 
            System.out.println(1000);
    }

    public synchronized modifyNum() {
        internalNum += 1;
    }

    public void run() {
        // Some code
    }
}

Let's say code execution is split in two threads. Hypothetically, following sequence of events occurs:

  • First thread accesses the getNum method and caches the internalNum which is 0 at the moment.
  • At the very same time second thread accesses modifyNum method acquiring the lock, changes the internalNum to 1 and exits releasing the lock.
  • Now, first thread continues it execution and prints the internalNum.

The question is what will get printed on the console?

My guess is that this hypothetical example will result in 1000 being printed on the console because read and write flushes are only forced on a particular thread when entering or leaving the synchronized block. Therefore, first thread will happily use it's cached value, not knowing it was changed.

I am aware that making internalNum volatile would solve the possible issue, however I am only wondering weather it is really necessary.

1

There are 1 answers

4
davidxxx On

Let's say code execution is split in two threads. It doesn't exit. However a ressource (method, fields) may be accessed in concurrent way by two threads.

I think you mix things. Your class extends Thread but your question is about accessing to a resource of a same instance by concurrent threads.

Here is the code adapted to your question.

A shared resource between threads :

public class SharedResource{
    private int internalNum;

    public void getNum() {
        if (internalNum > 1)
            System.out.println(internalNum);
        else 
            System.out.println(1000);
    }

    public synchronized modifyNum() {
        internalNum += 1;
    }

    public void run() {
        // Some code
    }   
}

Threads and running code :

public class ThreadForExample extends Thread {

    private SharedResource resource;

    public ThreadForExample(SharedResource resource){
       this.resource=resource;
    }

    public static void main(String[] args){
       SharedResource resource = new SharedResource();
       ThreadForExample t1 = new ThreadForExample(resource);
       ThreadForExample t2 = new ThreadForExample(resource);
       t1.start();
       t2.start();
    }
}

Your question :

Hypothetically, following sequence of events occurs:

First thread accesses the getNum method and caches the internalNum which is 0 at the moment. At the very same time second thread accesses modifyNum method acquiring the lock, changes the internalNum to 1 and exits releasing the lock. Now, first thread continues it execution and prints the internalNum

In your scenario you give the impression that the modifyNum() method execution blocks the other threads to access to non synchronized methods but it is not the case.
getNum() is not synchronized. So, threads don't need to acquire the lock on the object to execute it. In this case, the output depends simply of which one thread has executed the instruction the first :

internalNum += 1;

or

 System.out.println(internalNum);