Search code examples
javamultithreadingconcurrencyjava.util.concurrent

How can i synchronize the getters without having an incoherent state?


I tried to synchronize the getters with adding synchronized to the methods but i have always John Odd and Jane Doe. Any suggestion how can i synchronize the two Strings in that case ?

this is my code :

public class HonorBoard {
    private volatile String firstName;
    private volatile String lastName;


    public void set(String firstName, String lastName) {
        synchronized (this) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    private synchronized String getFirstName() {
        return firstName ;
    }

    private synchronized String getLastName() {
        return lastName;
    }

    @Override
    public synchronized String toString() {
        return firstName + ' ' + lastName;
    }

    public static void main(String[] args) {
        HonorBoard board = new HonorBoard();
        new Thread(() -> {
            for (;;) {
                board.set("John", "Doe");
            }
        }).start();

        new Thread(() -> {
            for (;;) {
                board.set("Jane", "Odd");
            }
        }).start();

        new Thread(() -> {
            for (;;) {
                System.out.println(board.getFirstName() + ' ' + board.getLastName());
            }
        }).start();
    }

}

Solution

  • The culprit is in your printing thread:

    new Thread(() -> {
        for (;;) {
            System.out.println(board.getFirstName() + ' ' + board.getLastName());
        }
    }).start();
    

    There is a chance that the internal state of board has changed just in between board.getFirstName() and board.getLastName().

    You could fix this issue in 2 ways.

    • Either by putting a synchronized(board) { ... } around it

      new Thread(() -> {
          for (;;) {
              synchronized (board) {
                  System.out.println(board.getFirstName() + ' ' + board.getLastName());
              }
          }
      }).start();
      
    • or by using board.toString() instead, which you did already synchronize properly.

      new Thread(() -> {
          for (;;) {
              System.out.println(board.toString());
          }
      }).start();