package cn.hutool.cache;
import cn.hutool.cache.impl.LRUCache;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 见:https://github.com/dromara/hutool/issues/1895
* 并发问题测试,在5.7.15前,LRUCache存在并发问题,多线程get后,map结构变更,导致null的位置不确定,
* 并可能引起死锁。
*/
public class LRUCacheTest {
@Test
@Ignore
public void putTest(){
//https://github.com/dromara/hutool/issues/2227
final LRUCache cache = CacheUtil.newLRUCache(100, 10);
for (int i = 0; i < 10000; i++) {
//ThreadUtil.execute(()-> cache.put(RandomUtil.randomString(5), "1243", 10));
ThreadUtil.execute(()-> cache.get(RandomUtil.randomString(5), ()->RandomUtil.randomString(10)));
}
ThreadUtil.sleep(3000);
}
@Test
public void readWriteTest() throws InterruptedException {
final LRUCache cache = CacheUtil.newLRUCache(10);
for (int i = 0; i < 10; i++) {
cache.put(i, i);
}
final CountDownLatch countDownLatch = new CountDownLatch(10);
// 10个线程分别读0-9 10000次
for (int i = 0; i < 10; i++) {
final int finalI = i;
new Thread(() -> {
for (int j = 0; j < 10000; j++) {
cache.get(finalI);
}
countDownLatch.countDown();
}).start();
}
// 等待读线程结束
countDownLatch.await();
// 按顺序读0-9
final StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb1.append(cache.get(i));
}
Assert.assertEquals("0123456789", sb1.toString());
// 新加11,此时0最久未使用,应该淘汰0
cache.put(11, 11);
final StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb2.append(cache.get(i));
}
Assert.assertEquals("null123456789", sb2.toString());
}
@Test
public void issue2647Test(){
final AtomicInteger removeCount = new AtomicInteger();
final LRUCache cache = CacheUtil.newLRUCache(3,1);
cache.setListener((key, value) -> {
// 共移除7次
removeCount.incrementAndGet();
//Console.log("Start remove k-v, key:{}, value:{}", key, value);
});
for (int i = 0; i < 10; i++) {
cache.put(StrUtil.format("key-{}", i), i);
}
Assert.assertEquals(7, removeCount.get());
Assert.assertEquals(3, cache.size());
}
}