如果必须将setter值写入文件,如何确保数据一致性?

How can I ensure data consistency if a setter value must be written into a file?

我正在使用 Preferences 来存储应用程序设置。我的 java class 在程序启动时读取设置,然后数据可以通过简单的 getters 用于其他 classes。

现在我也想实现 setters,因为用户可以更改程序中的一些首选项,因此从另一个 java class 调用 setter 是一个更改首选项的简单方法。

如果我更改了我的首选项中的值,我如何确保首选项中的数据和 class 中的数据一致?我应该只将数据存储在运行时对象和首选项中的 setter 中吗?

最重要的是: 在将数据写入首选项之前,我如何确保没有调用 getter ?我需要如何同步它们?

这里只是一个非常简单的例子来说明这个问题:

private static final Preferences PREFERENCES = //here are valid preferences
private static final String KEY = //Some path to the attribute

private static PrefManager prefManager = new PrefManager();

private String serverIP;

private PrefManager() {
    this.serverIP = PREFERENCES.get(KEY, "");
}


public static void setServerIP(String serverIP) {
    // How do I synchronize the PREFERENCE object and this setter to prevent getter
    // calls between put and = call here?
    PREFERENCES.put(KEY, serverIP);
    prefManager.serverIP = serverIP;
}

在解决您的竞争条件方面,您可以创建自己的首选项扩展并添加 synchronized 来设置和获取。有两种创建首选项扩展的方法:在内部使用映射并将所有键值复制到那里,或者创建外观。

关于如何保持应用程序的一致性:答案是 MVC 的控制器部分

立面示例

我已经从首选项中复制了所有方法并将它们添加到此处。您可以看到构造函数采用 Preferences 参数,它将成为实现此外观中所有方法的参考(请参阅前两个方法 absolutePath() 和 addNodeChangeListener(...) 以获取有关如何实现的示例)也请注意,方法 putget 已同步。因此,如果任何线程正在调用 put,则任何其他调用 get 的线程将等待 put 完成。 (您可能还想将 synchronized 添加到其他方法)

===================

public class MyPrefsFacade extends Preferences {
    private Preferences p;

    public MyPrefsFacade(Preferences prefs) {
      p = prefs;
    }

    public String   absolutePath() { return p.absolutePath(); }
    public void addNodeChangeListener(NodeChangeListener ncl) { p.addNodeChangeListener(ncl); }
    public void addPreferenceChangeListener(PreferenceChangeListener pcl)
    public String[] childrenNames()
    public void clear()
    public void exportNode(OutputStream os)
    public void exportSubtree(OutputStream os)
    public void flush()
    public synchronized String  get(String key, String def)
    public boolean  getBoolean(String key, boolean def)
    public byte[]   getByteArray(String key, byte[] def)
    public double   getDouble(String key, double def)
    public float    getFloat(String key, float def)
    public int  getInt(String key, int def)
    public long getLong(String key, long def)
    public boolean  isUserNode()
    public String[] keys()
    public String   name()
    public Preferences  node(String pathName)
    public boolean  nodeExists(String pathName)
    public Preferences  parent()
    public synchronized void    put(String key, String value)
    public void putBoolean(String key, boolean value)
    public void putByteArray(String key, byte[] value)
    public void putDouble(String key, double value)
    public void putFloat(String key, float value)
    public void putInt(String key, int value)
    public void putLong(String key, long value)
    public void remove(String key)
    public void removeNode()
    public void removeNodeChangeListener(NodeChangeListener ncl)
    public void sync()
    public String   toString()
}