MyBatis version
3.5.4
Database vendor and version
Test case or example project
MapperProxy#cachedInvoker {methodCache.computeIfAbsent} In ConcurrentHashMap#computeIfAbsent, the following code will cause lock acquire: [ else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { boolean added = false; // Here, even if the method and corresponding MapperMethodInvoker already exist synchronized (f) { ] I think, for mybatis, this lock is not necessary, maybe should change the code like follow: [ MapperMethodInvoker invoker = methodCache.get(method); if (invoker == null) { MapperMethodInvoker newInvoker = ....... MapperMethodInvoker old = methodCache.putIfAbsent(newInvoker); if (old != null) { invoker = old; } } return invoker; ]
Steps to reproduce
Expected result
Actual result
Comment From: harawata
That is a JDK's issue rather than MyBatis'. And it actually is fixed in JDK 9 and the backport to JDK 8 is also planned, it seems.
As MyBatis still supports Java 8, I thought about adding a preliminary check as you proposed, but it didn't make much difference (here is the JMH project that I used). Do you have any benchmark data proving otherwise?
[EDIT] Well, the benchmark should be done using multiple threads, obviously. I will re-test later.
Comment From: harawata
@lixinwen ,
I updated the JMH project and verified the effect of the preliminary check under heavy load. Does #1934 look OK to you?
Comment From: lixinwen
@harawata Thank you, this what i want.
Comment From: harawata
You can verify the fix with 3.5.5-SNAPSHOT. Thank you for taking the time to report, @lixinwen !