In my application the ehcache is configured as below.
AppDataRegion.java
//import statements.
public class AppDataRegion{
//Variable for region identifier.
private String appRegionId;
// constructor sets the appRegionId;
//obtained from the system current time.
public AppDataRegion(){
appRegionId = String.valueOf(System.currentTimeMillis());
}
//Variable for cachemanager
// injected by spring DI from context xml
Private CacheManager appCacheMngr;
//necessary getter / setter methods for variable cachemanager
//necessary getter / setter methods for variable appRegionId
//method to create a region in cache using the appRegionId value
private createRegion(){
if (!appCacheMngr.cacheExists(appRegionId)){
try {
appCacheMngr.addCache(appRegionId);
catch (exc){
//exception handled
}
}
}
public Cache getRegion(){
if(appCacheMngr == null || !appCacheMngr.cacheExists(appRegionId)){
createRegion();
}
return appCacheMangr.getCache(appRegionId);
}
private createCustRegion(){
try{
Cache custCache = appCacheMngr.getCache(“custdiskCache”);
If(null == custCache.addCache(custCache);
}catch (exp){
//handled the exceptions
}
retrun appCacheMngr.getCache(“custdiskCache”);
}
}
Spring configuration
<bean id="appDataStoreService" class="com.app.cache.AppDataStoreService" >
<property name="appDataStoreRegion" ref="appDataStoreRegion"/>
</bean>
<bean id="appDataStoreRegion" class="com.app.cache.AppDataStoreRegion">
<property name="appcacheManager" ref="cacheManager"/>
</bean>
<bean id="cacheManager" class="net.sf.ehcache.CacheManager" factory-method="create">
<constructor-arg index="0" type="java.net.URL" value="classpath:ehcache-app.xml" />
</bean>
//There is a service layer for the app data store region.
public class AppDataStoreService{
//datastoreregion variable declaration
private AppDataStoreRegion appDataStoreRegion;
public void storeCustObjInCache(String id, Object obj){
Cache region = appDataStoreRegion.getCustRegion();
If(region != null && id !=null && region.isElementInMemory(id)){
region.remove(id);
}
Element ele = new Element(id, obj);
If(region != null) region.put(ele);
}
}
Within the application after populating the data in the DTO object I call the storeCustObjInCache() method of appDataStoreService class to write the content to disk.
The ehcache is configured as singleton rather than instance.
The web application uses struts (2.3.20) framework for web flow and Spring framework (4.1.2) for DI object management.
Also JSP for UI we iterate the use bean object which has list to display contents.
We migrated to ehcache 2.9.0 from 1.2.2 just changing the jar and configuration in spring xml context. After the migration we started getting the below exception frequently.
net.sf.ehcache.CacheException: Failed to serialize element due to ConcurrentModificationException. This is frequently the result of inappropriately sharing thread unsafe object (eg. ArrayList, HashMap, etc) between threads at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:405) at net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:385) at net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:477) at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1071) at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1055) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.util.ConcurrentModificationException at java.util.ArrayList.writeObject(ArrayList.java:766) at sun.reflect.GeneratedMethodAccessor8008.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441) at net.sf.ehcache.Element.writeObject(Element.java:875)
My understanding why this happens is, when the ehcache is trying to write to the disk another thread is modifying the serialized list.I couldn't find out which thread and the possibility for it.
Is there an example on how to use the ehcache using programmatically like this without annotation within spring.
And any insight on how to identify the thread that causing this issue
You have two options:
I would favour option 2 if you can refactor your application that way.
This problem is absolutely not caused by the way you wire the different participant objects, which by the way does not use annotations in the example provided.