英文:
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(...) 的实现示例)。还请注意,方法 put
和 get
已经被同步化。因此,如果任何线程调用了 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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论