Skip to content

Concurrency problems caused by using guava cache's get() and getIfPresent() methods under multithreading #8090

@ZME7777777

Description

@ZME7777777

Guava Version

30.1

Description

Concurrency problems caused by using guava cache's get() and getIfPresent() methods under multithreading

Example

`import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;

public class Main {

    final Cache<String, Map<Integer, Integer>> cache = CacheBuilder.newBuilder().initialCapacity(100).build();

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startLatch = new CountDownLatch(1);
        int count = 10;
        Main main2 = new Main();
        CountDownLatch doneLatch = new CountDownLatch(count);
        for (int i = 0; i < count; i++) {
            Thread thread = new Thread(() -> {
                try {
                    startLatch.await();
                    main2.test();
                } catch (InterruptedException | ExecutionException e) {
                    throw new RuntimeException(e);
                } finally {
                    doneLatch.countDown();
                }
            });
            thread.setName("T" + (i + 1));
            thread.start();
        }
        startLatch.countDown();
        doneLatch.await();
    }

    public void test() throws ExecutionException {
        Map<Integer, Integer> target = cache.get("test", HashMap::new);
        int i = target.size();
        for (; i < 5; i++) {
            target.put(i, i);
        }
        System.out.println(target + ":" + cache.getIfPresent("test"));
    }
    
}`

result:
{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:null

{0=0, 4=4, 1=1, 2=2, 3=3}:{0=0, 4=4, 1=1, 2=2, 3=3}

Expected Behavior

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;

public class Main1 {

final Cache<String, Map<Integer, Integer>> cache = Caffeine.newBuilder().build();

public static void main(String[] args) throws InterruptedException {
    CountDownLatch startLatch = new CountDownLatch(1);
    int count = 10;
    Main1 main2 = new Main1();
    CountDownLatch doneLatch = new CountDownLatch(count);
    for (int i = 0; i < count; i++) {
        Thread thread = new Thread(() -> {
            try {
                startLatch.await();
                main2.test();
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            } finally {
                doneLatch.countDown();
            }
        });
        thread.setName("T" + (i + 1));
        thread.start();
    }
    startLatch.countDown();
    doneLatch.await();
}

public void test() throws ExecutionException {
    Map<Integer, Integer> target = cache.get("test", s -> new HashMap<>());
    int i = target.size();
    for (; i < 5; i++) {
        target.put(i, i);
    }
    System.out.println(target + ":" + cache.getIfPresent("test"));
}

}

result:
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}
{0=0, 1=1, 2=2, 3=3, 4=4}:{0=0, 1=1, 2=2, 3=3, 4=4}

Actual Behavior

getIfPresent cannot be immediately visible

Packages

com.google.common.cache

Platforms

Java 8

Checklist

  • I agree to follow the code of conduct.

  • I can reproduce the bug with the latest version of Guava available.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type=defectBug, not working as expected

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions