我如何在没有不连贯状态的情况下同步吸气剂?

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

我试图通过向方法中添加 synchronized 来同步 getter,但我总是 John OddJane Doe。任何建议我如何在这种情况下同步两个字符串?

这是我的代码:

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();
    }

}

我认为两种 getter 方法是不可能的。我会将 getFirstname 和 getLastname 替换为 getName 和 return 一个双元素字符串数组或一个 java 将名字和姓氏保存在一起的 bean。在该 getter 方法中,您将使用同步块,就像在您的 setter 中一样,在该块中,您构建数组或 bean。我认为这应该有效。

罪魁祸首在您的打印线程中:

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

有可能 board 的内部状态发生了变化 就在 board.getFirstName()board.getLastName().

之间

您可以通过两种方式解决此问题。

  • 要么在它周围放一个 synchronized(board) { ... }

    new Thread(() -> {
        for (;;) {
            synchronized (board) {
                System.out.println(board.getFirstName() + ' ' + board.getLastName());
            }
        }
    }).start();
    
  • 或使用 board.toString(),您已经正确同步了。

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