我有一种情况,我从yaml文件中读取数据对应用程序很重要的数据,因为它在多个类中使用。这是我的代码:
public class CredentialsReader {
private UserCredentials credentials;
private boolean isReading = false;
public CredentialsReader() {
}
public void readCredentials() {
Runnable readerTask = new Runnable() {
@Override
public void run() {
isReading = true;
parseCredentials();
isReading = false;
System.err.println("Parsed credentials");
}
};
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(readerTask, 0, 60, TimeUnit.SECONDS);
}
private void parseCredentials() {
final File f = new File("/home/dev/IdeaProjects/server/src/main/resources/credentials.yaml");
try {
UserCredentials userCredentials = new ObjectMapper().readValue(f, UserCredentials.class);
this.credentials = userCredentials;
System.out.println(this.credentials.getUsername() + ", " + this.credentials.getPassword());
} catch (IOException e) {
e.printStackTrace();
}
}
public UserCredentials getCredentials() { return this.credentials; }
}
如您所见,我每分钟阅读数据,我的问题是:
我可以延迟getCredentials的返回值,因此当调用该方法时,我检查isReading
是否为true
,然后延迟返回,以便我可以保证呼叫者始终获得YAML文件的实际状态?
我认为对于类似情况有适当的锁,但这似乎同步就足够了。
synchronized private void parseCredentials() {...}
synchronized public UserCredentials getCredentials() { ... }
通过声明这些方法一次仅同步一个线程,将能够输入该方法,本质上是一个障碍。这意味着,副标题可能必须等待getCredentials,但是GetCredentials非常快,您永远不会注意到。
将同步在凭证上的实例上,因此,如果您使用多个,则可能需要同步其他内容。如前所述,评论最好在私人对象而不是实例本身上同步。这是一个很小的变化:
public class CredentialsReader {
private UserCredentials credentials;
private boolean isReading = false;
final private Object lock = new Object();
...
然后从方法签名中删除同步并在体内添加同步调用。
private void parseCredentials() {
synchronize(lock){
//original code goes here.
}
}
另外,isReading
应该是挥发的。
我不建议手动执行此操作,您可以使用jdk中提供的init value 1
的 CountDownLatch
。
您可以让读者打电话给await
,并在准备数据后打电话给countDown
。
,读者总是可以获取完全初始化的数据。