javaconcurrencyguavagoogle-guava-cache

Cache concurrency RemovalListener


public class testCache {
    static final Striped<Lock> lockStriped = Striped.lazyWeakLock(1024);
    static final Cache<Integer, Holder> cache = CacheBuilder.newBuilder().concurrencyLevel(50).expireAfterAccess(10000l, TimeUnit.DAYS).maximumSize(5000)
            .removalListener((RemovalListener<Integer, Holder>) removalNotification -> {
                System.out.println("tests");
                System.out.println(removalNotification.getCause());
                System.out.println(removalNotification.getKey());
                System.out.println(removalNotification.getValue());
            }).build();

    public static void main(String[] args) {
        System.out.println("Starting");
        ExecutorService executor = Executors.newFixedThreadPool(40);

        for (int i = 0; i < 1000; i++) {
            for (int j = 0; j < 1000; j++) {
                int finalI = i;
                executor.execute(() -> setCounter(finalI));
                int finalI1 = i;
                executor.execute(() -> setFlag(finalI1));
            }
        }

        for (int i = 0; i < 1000; i++) {
            cache.invalidate(i);
        }
        executor.shutdown();
        while (!executor.isTerminated()) {
        }

    }

    private static void setFlag(int id) {
        Lock lock = lockStriped.get(id);
        try {
            lock.lock();
            Holder holder = cache.getIfPresent(id);
            if (holder == null) {
                holder = new Holder();
                holder.setFlag(true);
                cache.put(id, holder);
            } else {
                holder.setFlag(id % 2 != 0);
            }
        } finally {
            lock.unlock();
        }
    }

    private static void setCounter(int id) {
        Lock lock = lockStriped.get(id);
        try {
            lock.lock();
            Holder holder = cache.getIfPresent(id);
            if (holder == null) {
                holder = new Holder();
                int i = holder.getCounter() + 1;
                holder.setCounter(i);
                cache.put(id, holder);
            } else {
                int i = holder.getCounter() + 1;
                holder.setCounter(i);
            }
        } finally {
            lock.unlock();
        }
    }
}

Hi here is simple code. Question is why some values from cache are different as I expected. I think there should be 1000 entries in cahce each with counter as 1000, but processing ends on

Holder{counter=1000, flag=false}
tests
EXPLICIT
105
Holder{counter=985, flag=true}
tests
EXPLICIT
106
Holder{counter=1000, flag=false}
tests
EXPLICIT
107
Holder{counter=717, flag=true}

Where is the problem it is good way to write this kind test or I missed something.


Solution

  • Changing code

       for (int i = 0; i < 1000; i++) {
                    cache.invalidate(i);
                }
       executor.shutdown();
       while (!executor.isTerminated()) {}
    

    To

    executor.shutdown();
    while (!executor.isTerminated()) {}
    
    for (int i = 0; i < 1000; i++) {
      cache.invalidate(i);
    }
    

    Resolved my problem