0

Here is a situation. I have a non blocking stream of String. These Strings can repeat so I want to setup a cache that keeps the record of last 10 seconds of String that were recieved. After enabling the cache the system's network has improved drastically but at the cost of performance. Here is what I am using to cache:

@Getter
@ToString
class StringWrapper implements Comparable<StringWrapper> {
    private String string;
    private long time;
    private StringWrapper() {}
    public StringWrapper(String string) {
        this();
        this.string = string;
        time = System.currentTimeMillis();
    }
    @Override
    public int compareTo(StringWrapper o) {
        return getTime() > o.getTime() ? 1 : getTime() < o.getTime() ? -1: 0;
    }
    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof StringWrapper)) { throw new IllegalArgumentException(); }
        StringWrapper sw = (StringWrapper) obj;
        return string.equals(sw.getString());
    }
}

class SetProxy extends HashSet<StringWrapper> {
    private interface Thunk { public void exec(); }
    // expire by ten second
    private final Thunk thunk = () -> removeIf(sw -> System.currentTimeMillis() - sw.getTime() > 1000 * 10);
    @Override
    public boolean add(StringWrapper e) {
        thunk.exec();
        return super.add(e);
    }
    //... similar method overrides that invoke thunk internally
}

I have to invoke thunk.exec() on each method that add or removes from the Set otherwise the memory consumption will increase. The problem is with removeIf inside thunk#exec, it iterates over the set again and again.

I thought of having a seperate scheduler that executes every one second to remove the expired String but it comes along with concurrency problems.

Can someone suggest a better workaround?

  • Why have your separate scheduler execute every 1 sec. Why not have a ScheduledExecutorService that calls remove in the allotted timeout. What do you mean by "at the cost of performance"? – matt May 11 '20 at 10:06
  • @matt `thunk#exec` executes on each `add`, this steals some computation cycles because there are nearly 2K string received each second. –  May 11 '20 at 10:09
  • How about Guava? https://stackoverflow.com/a/3802420/2067492 Also, you've left off the thunk.exec() method. It sounds like thunk.exec is for removing the expired entries? – matt May 11 '20 at 10:14
  • @matt Perfect. Thanks for it. And yes, `thunk#exec` is removing the expired entries. –  May 11 '20 at 10:17

0 Answers0