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

huangapple go评论91阅读模式
英文:

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

问题

I am using Preferences to store application settings. My java class reads the settings at program start and then the data is available with simple getters for other classes.

现在我也想要实现setter方法,因为用户可以在程序中更改一些偏好设置,因此从另一个java类中调用setter方法是更改偏好设置的一种简便方法。

如果我更改了偏好设置中的某个值,如何确保偏好设置中的数据和类中的数据保持一致?我应该只是在setter方法中存储数据在运行时对象和偏好设置中吗?

最重要的是:
如何确保在数据写入偏好设置之前不会调用getter方法?我需要如何同步它们?

这里只是一个非常简单的示例来展示这个问题:

private static final Preferences PREFERENCES = //这里是有效的偏好设置
private static final String KEY = //属性的某些路径

private static PrefManager prefManager = new PrefManager();

private String serverIP;

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

public static void setServerIP(String serverIP) {
    // 在这里如何同步PREFERENCE对象和这个setter方法,以防止在put和=调用之间调用getter方法?
    PREFERENCES.put(KEY, serverIP);
    prefManager.serverIP = serverIP;
}

(Note: The code you provided contains HTML entities for double quotes ", which are not necessary in Java. I've removed them in the translation.)

英文:

I am using Preferences to store application settings. My java class reads the settings at program start and then the data is available with simple getters for other classes.

Now I also want to implement setters because the user can change some Preferences in the program and therefore calling a setter from another java class is an easy method to change the preferences.

If I change a value in my Preferences, how can I ensure, that the data in the Preferences and in the class are consistent? Should I just store the data within the setter in the runtime object and in the Preferences?

And most importantly:
How can I ensure, that no getter is called, before the data is written into the preferences? How do I need to synchronize them?

Here is just a really simple example to display the issue:

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

答案1

得分: 1

关于解决竞态条件的问题,您可以创建自己的 Preferences 扩展,并在设置和获取方法中添加 synchronized 关键字。创建偏好设置扩展有两种方式:一种是在内部使用映射(map)并将所有键值对复制到其中,另一种是创建一个外观(facade)。

关于如何保持应用程序的一致性:答案是 MVC 架构中的控制器(Controller)部分。

外观模式示例

我已经复制了所有的 Preferences 方法并添加到了这里。您可以看到构造函数接受一个 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()
}
英文:

In terms of solving your race condition, you can create your own Preferences extension and add synchronized to set and get. There are two ways to create a preference extension: use a map internally and copy all key - values there, or create a facade.

In terms of how do you keep your application consistent: The answer to this is the Controller piece of MVC

Example of facade

I've copied all of the methods from Preferences and added them here. You can see that the constructor takes a Preferences parameter, which is going to be the reference implementing all methods in this facade (see the first two methods absolutePath() and addNodeChangeListener(...) for examples of how this should be implemented) Also note that the methods put and get have been synchronized. So if any thread is calling put, any other thread calling get will wait until put is done. (You may want to add synchronized to other methods as well)

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

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

huangapple
  • 本文由 发表于 2020年4月7日 22:27:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/61082344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定