在项目用到 EhCache 来cache 从数据库中query 出来的reference 数据。 按理说ehcahce 非常成熟了但是在用的它的addCacheIfAbsent api 时, 居然碰到它不是线程安全的。 从它api 字面上来说绝对不应该是线程不安全的, 放狗一搜果然是个bug。 这么低级的bug 还是在最新的版本2.7.0 才fix。 但是我们项目只用到它的ehcache-core.jar 不想用太多它的特性, 下了个 ehcache-core.2.6.9.jar 来看看 release 日期是 2041-4-8 但愿没有问题哈。
在它的网站上找的bug 的链接 https://jira.terracotta.org/jira/browse/EHC-970, 其中有段测试代码。 其中的代码居然有问题, 所以就改下 放到这个地方看看有没有大家需要的。
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import org.junit.Test;
public class EhcacheTest {
private static final String CACHE_NAME = "test-cache";
private CacheManager cm ; //= CacheManager.getInstance();
private final AtomicLong counter = new AtomicLong(0L);
private int maxEntriesLocalHeap = 20000;
private long maxBytesLocalHeap = 1024 * 1024 * 100;
private boolean isExpiryTimeFixed = true;
private int timeToIdleSeconds = 30 * 1000;
private int timeToLiveSeconds = 30 * 1000;
private boolean overflowToOffHeap = false;
private boolean eternal = false;
public Configuration getEhcacheConfig() {
CacheConfiguration dcc = new CacheConfiguration();
dcc.setMaxEntriesLocalHeap(maxEntriesLocalHeap);
if (maxEntriesLocalHeap == 0) {
dcc.setMaxBytesLocalHeap(maxBytesLocalHeap);
}
dcc.setTimeToIdleSeconds(timeToIdleSeconds);
dcc.setTimeToLiveSeconds(timeToLiveSeconds);
dcc.setOverflowToOffHeap(overflowToOffHeap);
dcc.setEternal(eternal);
Configuration configuration = new Configuration();
configuration.setDefaultCacheConfiguration(dcc);
configuration.setUpdateCheck(false);//application instant can not connect web site
return configuration;
}
@Test
public void test_10000_Executions() throws InterruptedException {
final Executor executor = Executors.newFixedThreadPool(10);
cm = CacheManager.create(getEhcacheConfig());
for (int i = 0; i < 100000; i++) {
executor.execute(new CreateAndRemoveCache());
if ((i%1000) == 0) {
}
}
while(counter.get() < 100000) {
Thread.sleep(1000L);
System.out.println("i=" + counter.get());
}
}
public class CreateAndRemoveCache implements Runnable {
public CreateAndRemoveCache() {
}
@Override
public void run() {
cm.addCacheIfAbsent(CACHE_NAME);
cm.removeCache(CACHE_NAME);
counter.addAndGet(1);
}
}
}
这段代码在 2.5.1 下会抛出 Item 已经存在的exception , 在 2.6.9 就不会。 好吧, 就暂时升级jar 来fix 这个问题把。