java.lang.IllegalStateException

Spring JIRA | Alexander Zagumennikov | 3 years ago
  1. 0

    Hi I tried to use spring cache api in a web project, but unfortunately I faced with concurrency issues. The task was to make 'blocking' cache. It means when multiple threads simultaneously try to access cache, only one thread loads data from storage, other threads wait for this thread, and once data is loaded, all threads return it. I think it's a common task for most web projects. I haven't found anything about cache behavior in multithread environment in spring documentation, so spring has no cache synchronizations and when multiple threads access cache, they will be passed to cache back-end, and load data from storage multiple times (if back-end has no synchronization). In spring context xml: {code:xml} ... <cache:annotation-driven/> <bean name="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="/WEB-INF/ehcache.xml"/> </bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehCacheManager"/> </bean> <bean class="test.SomeCache"/> ... {code} ehcache.xml: {code:xml} <ehcache> <cache name="someCache" maxBytesLocalHeap="50m"/> </ehcache> {code} SomeCache.java: {code:java} public class SomeCache { @Cacheable("someCache") public String findResult(String id) { System.out.println("start find result"); try { Thread.sleep(10000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("end find result"); return "result"; } } {code} In mvc controller: {code:java} ... for (int i = 0; i < 10; ++i) { new Thread(new Runnable() { public void run() { System.out.println("before find result"); someCache.findResult("id"); System.out.println("after find result"); } }).start(); } ... {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result start find result start find result start find result start find result start find result start find result start find result start find result start find result end find result end find result end find result end find result end find result end find result end find result end find result end find result end find result after find result after find result after find result after find result after find result after find result after find result after find result after find result after find result {code} As we can see - no synchronization, cachable methods enters multiple times. Second approach was to configure cache back-end - EhCache in my case - to synchronize access to storage. I configured EhCache to use BlockingCache decorator, and it seemed to work fine, except of one fatal issue: if exception is thrown during data loading, BlockingCache will never release the lock (it is meant that caller should put null to cache on exception). So, spring cache facade does not support that case. EhCache also provides SelfPopulatingCache decorator that does exception handling stuff, but again spring does not support it because it requires CacheEntryFactory to be passed in constructor. ehcache.xml: {code:xml} <ehcache> <cache name="someCache" maxBytesLocalHeap="50m"> <cacheDecoratorFactory class="test.BlockingCacheDecoratorFactory"/> </cache> </ehcache> {code} BlockingCacheDecoratorFactory.java: {code:java} package test; import net.sf.ehcache.Ehcache; import net.sf.ehcache.constructs.CacheDecoratorFactory; import net.sf.ehcache.constructs.blocking.BlockingCache; import java.util.Properties; public class BlockingCacheDecoratorFactory extends CacheDecoratorFactory { @Override public Ehcache createDecoratedEhcache(Ehcache cache, Properties properties) { return new BlockingCache(cache); } @Override public Ehcache createDefaultDecoratedEhcache(Ehcache cache, Properties properties) { return new BlockingCache(cache); } } {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result end find result after find result after find result after find result after find result after find result after find result after find result after find result after find result after find result {code} Seems fine, but what if we have an exception? SomeCache.java: {code:java} package test; import org.springframework.cache.annotation.Cacheable; public class SomeCache { @Cacheable("someCache") public String findResult(String id) { System.out.println("start find result"); throw new IllegalStateException(); } } {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result Exception in thread "Thread-36" java.lang.IllegalStateException at test.SomeCache.findResult(SomeCache.java:11) at test.SomeCache$$FastClassByCGLIB$$96e26c72.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:701) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:58) at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:211) at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:634) at test.SomeCache$$EnhancerByCGLIB$$dc1816.findResult(<generated>) ... at java.lang.Thread.run(Thread.java:722) {code} And if we try to call it second time: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result {code} Only one thread exited with exception, others are deadlocked. Details about ehcache behavior here: http://ehcache.org/apidocs/net/sf/ehcache/constructs/blocking/BlockingCache.html#get(java.lang.Object) http://grepcode.com/file/repo1.maven.org/maven2/net.sf.ehcache.internal/ehcache-core/2.7.4/net/sf/ehcache/constructs/blocking/SelfPopulatingCache.java#SelfPopulatingCache.get%28java.lang.Object%29 As a result - I can't use spring caching facade with annotations to make a blocking cache. I see two ways to resolve the situation: 1. Support EhCache BlockingCache decorator - put null on exception, don't know if this could be achieved in general way, not affecting other cache back-ends. 2. Implement blocking cache in spring - it is better approach in my opinion. In this case we will have blocking cache with any back-end. Related issues: https://jira.spring.io/browse/SPR-9588 https://jira.spring.io/browse/SPR-9254 https://jira.spring.io/browse/SPR-9304

    Spring JIRA | 3 years ago | Alexander Zagumennikov
    java.lang.IllegalStateException
  2. 0

    Hi I tried to use spring cache api in a web project, but unfortunately I faced with concurrency issues. The task was to make 'blocking' cache. It means when multiple threads simultaneously try to access cache, only one thread loads data from storage, other threads wait for this thread, and once data is loaded, all threads return it. I think it's a common task for most web projects. I haven't found anything about cache behavior in multithread environment in spring documentation, so spring has no cache synchronizations and when multiple threads access cache, they will be passed to cache back-end, and load data from storage multiple times (if back-end has no synchronization). In spring context xml: {code:xml} ... <cache:annotation-driven/> <bean name="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="/WEB-INF/ehcache.xml"/> </bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehCacheManager"/> </bean> <bean class="test.SomeCache"/> ... {code} ehcache.xml: {code:xml} <ehcache> <cache name="someCache" maxBytesLocalHeap="50m"/> </ehcache> {code} SomeCache.java: {code:java} public class SomeCache { @Cacheable("someCache") public String findResult(String id) { System.out.println("start find result"); try { Thread.sleep(10000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("end find result"); return "result"; } } {code} In mvc controller: {code:java} ... for (int i = 0; i < 10; ++i) { new Thread(new Runnable() { public void run() { System.out.println("before find result"); someCache.findResult("id"); System.out.println("after find result"); } }).start(); } ... {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result start find result start find result start find result start find result start find result start find result start find result start find result start find result end find result end find result end find result end find result end find result end find result end find result end find result end find result end find result after find result after find result after find result after find result after find result after find result after find result after find result after find result after find result {code} As we can see - no synchronization, cachable methods enters multiple times. Second approach was to configure cache back-end - EhCache in my case - to synchronize access to storage. I configured EhCache to use BlockingCache decorator, and it seemed to work fine, except of one fatal issue: if exception is thrown during data loading, BlockingCache will never release the lock (it is meant that caller should put null to cache on exception). So, spring cache facade does not support that case. EhCache also provides SelfPopulatingCache decorator that does exception handling stuff, but again spring does not support it because it requires CacheEntryFactory to be passed in constructor. ehcache.xml: {code:xml} <ehcache> <cache name="someCache" maxBytesLocalHeap="50m"> <cacheDecoratorFactory class="test.BlockingCacheDecoratorFactory"/> </cache> </ehcache> {code} BlockingCacheDecoratorFactory.java: {code:java} package test; import net.sf.ehcache.Ehcache; import net.sf.ehcache.constructs.CacheDecoratorFactory; import net.sf.ehcache.constructs.blocking.BlockingCache; import java.util.Properties; public class BlockingCacheDecoratorFactory extends CacheDecoratorFactory { @Override public Ehcache createDecoratedEhcache(Ehcache cache, Properties properties) { return new BlockingCache(cache); } @Override public Ehcache createDefaultDecoratedEhcache(Ehcache cache, Properties properties) { return new BlockingCache(cache); } } {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result end find result after find result after find result after find result after find result after find result after find result after find result after find result after find result after find result {code} Seems fine, but what if we have an exception? SomeCache.java: {code:java} package test; import org.springframework.cache.annotation.Cacheable; public class SomeCache { @Cacheable("someCache") public String findResult(String id) { System.out.println("start find result"); throw new IllegalStateException(); } } {code} Result: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result start find result Exception in thread "Thread-36" java.lang.IllegalStateException at test.SomeCache.findResult(SomeCache.java:11) at test.SomeCache$$FastClassByCGLIB$$96e26c72.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:701) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:58) at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:211) at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:634) at test.SomeCache$$EnhancerByCGLIB$$dc1816.findResult(<generated>) ... at java.lang.Thread.run(Thread.java:722) {code} And if we try to call it second time: {code} before find result before find result before find result before find result before find result before find result before find result before find result before find result before find result {code} Only one thread exited with exception, others are deadlocked. Details about ehcache behavior here: http://ehcache.org/apidocs/net/sf/ehcache/constructs/blocking/BlockingCache.html#get(java.lang.Object) http://grepcode.com/file/repo1.maven.org/maven2/net.sf.ehcache.internal/ehcache-core/2.7.4/net/sf/ehcache/constructs/blocking/SelfPopulatingCache.java#SelfPopulatingCache.get%28java.lang.Object%29 As a result - I can't use spring caching facade with annotations to make a blocking cache. I see two ways to resolve the situation: 1. Support EhCache BlockingCache decorator - put null on exception, don't know if this could be achieved in general way, not affecting other cache back-ends. 2. Implement blocking cache in spring - it is better approach in my opinion. In this case we will have blocking cache with any back-end. Related issues: https://jira.spring.io/browse/SPR-9588 https://jira.spring.io/browse/SPR-9254 https://jira.spring.io/browse/SPR-9304

    Spring JIRA | 3 years ago | Alexander Zagumennikov
    java.lang.IllegalStateException
  3. Speed up your debug routine!

    Automated exception search integrated into your IDE

  4. 0

    Causes for IllegalStateException

    Stack Overflow | 4 years ago | Gokul Nath
    java.lang.IllegalStateException
  5. 0

    Grails, Tomcat deployment error

    Stack Overflow | 4 years ago | Eddard Stark
    java.lang.IllegalStateException

    Not finding the right solution?
    Take a tour to get the most out of Samebug.

    Tired of useless tips?

    Automated exception search integrated into your IDE

    Root Cause Analysis

    1. java.lang.IllegalStateException

      No message provided

      at test.SomeCache.findResult()
    2. test
      SomeCache$$FastClassByCGLIB$$96e26c72.invoke
      1. test.SomeCache.findResult(SomeCache.java:11)
      2. test.SomeCache$$FastClassByCGLIB$$96e26c72.invoke(<generated>)
      2 frames
    3. Spring Core
      MethodProxy.invoke
      1. org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
      1 frame
    4. Spring AOP
      ReflectiveMethodInvocation.proceed
      1. org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:701)
      2. org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
      2 frames
    5. Spring Context
      CacheInterceptor.invoke
      1. org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:58)
      2. org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:211)
      3. org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66)
      3 frames
    6. Spring AOP
      CglibAopProxy$DynamicAdvisedInterceptor.intercept
      1. org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
      2. org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:634)
      2 frames
    7. test
      SomeCache$$EnhancerByCGLIB$$dc1816.findResult
      1. test.SomeCache$$EnhancerByCGLIB$$dc1816.findResult(<generated>)
      1 frame