Java延迟返回值

时间:2019-05-21 07:23:50

标签: java multithreading

我有一种情况,我从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的实际状态。文件?

2 个答案:

答案 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

因此阅读器始终可以获取完全初始化的数据。