代码之家  ›  专栏  ›  技术社区  ›  Almas Abdrazak

使用decorators的简单缓存机制

  •  3
  • Almas Abdrazak  · 技术社区  · 6 年前

    我有一个简单的界面

    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 是可以喃喃自语的,为了正确使用多个线程,我创建了另一个decorator

    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 回复  |  直到 6 年前
        1
  •  2
  •   Rann Lifshitz rul    6 年前

    我建议通过双重检查锁机制同步缓存类,而不是使用额外的线程安全实现:

    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)。

    这应该符合你的需要。