Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Cache mechanizm using decorators

I have a simple interface

public interface Text {

    String asText() throws IOException;
}

And one implementation

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;
    }

}

This class is very simple, it reads text from a file then returns it as a string. In order to avoid reading from the file multiple times I want to create a second class that will decorate the original one

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;
    }

}

And now it work; however the result is muttable, and in order to work correctly with multiple threads i have created another 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();
        }
    }

}

But now my program will spend resources on synchronization each time I call asText() .

What is the best implementation of a caching mechanism in my situation?

like image 516
Almas Abdrazak Avatar asked Feb 06 '26 12:02

Almas Abdrazak


1 Answers

I would suggest making your cached class synchronized via the Double Check Lock mechanism, instead of using the additional implementation for thread safety:

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;
    }

}

There might be concerns using the DCL as seen here- but if they exist on your end, just comment and I'll post additional support (I believe that modern JVMs are better suited for handling DCLs).

This should be good for your needs.

like image 135
Rann Lifshitz Avatar answered Feb 09 '26 09:02

Rann Lifshitz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!