在项目用到 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 这个问题把。