使用装饰器的简单缓存机制

时间:2018-04-04 05:13:23

标签: java caching synchronization decorator

我有一个简单的界面

public interface Text {

    String asText() throws IOException;
}

一个实现

public final class TextFromFile implements Text{

    private final String path;

    public TextFromFile(final String pth) {
        this.path = pth;
    }

    @Override
    public String asText() throws IOException {
        final String text = Files.readAllLines(Paths.get(this.path))
                                 .stream()
                                 .collect(Collectors.joining(""));
        return text;
    }

}

这个类非常简单,它从文件中读取文本然后将其作为字符串返回。为了避免多次从文件中读取,我想创建一个将装饰原始文件的第二个类

public final class CachedText implements Text{

    private final Text origin;

    private String result;

    public CachedText(final Text orgn) {
        this.origin = orgn;
    }

    @Override
    public String asText() throws IOException {
        if(this.result == null){
            this.result = this.origin.asText();
        }
        return this.result;
    }

}

现在它起作用了;但result是可变的,为了正确使用多个线程,我创建了另一个装饰器

public final class ThreadSafeText implements Text{

    private final Text origin;

    public ThreadSafeText(final Text orgn) {
        this.origin = orgn;
    }



    @Override
    public String asText() throws IOException {
        synchronized(this.origin){
            return this.origin.asText();
        }
    }

}

但现在我的程序每次拨打asText()时都会在同步上花费资源。

在我的情况下,缓存机制的最佳实现是什么?

1 个答案:

答案 0 :(得分:2)

我建议通过Double Check Lock机制使您的缓存类同步,而不是使用额外的线程安全实现:

public final class CachedText implements Text{

    private final Text origin;

    private String result;

    public CachedText(final Text orgn) {
        this.origin = orgn;
    }

    @Override
    public String asText() throws IOException {
        if(this.result == null){
            synchronized(this) {
                if(this.result == null){
                    this.result = this.origin.asText();
                }
            }
        }
        return this.result;
    }

}

可能有人担心使用DCL here - 但如果它们存在于您的最后,只需发表评论,我会发布其他支持(我相信现代JVM更适合处理DCL)

这应该有利于您的需求。