我有一种情况,我从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的实际状态。文件?
答案 0 :(得分:3)
我认为对于类似的情况有适当的锁,但是似乎同步就足够了。
synchronized private void parseCredentials() {...}
synchronized public UserCredentials getCredentials() { ... }
通过声明那些仅一次同步一个线程的方法将能够进入该方法,这实际上是一个障碍。这意味着parseCredentials可能不得不等待getCredentials,但是getCredentials是如此之快,以至于您永远不会注意到。
这将在CredentialReader的一个实例上同步,因此,如果您使用多个实例,则可能要在其他对象上进行同步。如前所述,最好在私有对象上进行同步,而不要在实例本身上进行同步。这是一个小变化:
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
应该是易失的。
答案 1 :(得分:2)
我不建议手动执行此操作,您可以使用jdk中提供的CountDownLatch
且其初始值为1
。
一旦准备好数据,就可以让读者调用await
,而让作家调用countDown
。
因此阅读器始终可以获取完全初始化的数据。