Search code examples
javaserializationreplicationehcache

Error serializing element in ehcache


I get the following error, when puting an element in the ehcache. Does anyone have any idea why this error occures?

Thank you in advance.

This is put method:

  @SuppressWarnings("unchecked")
  @Override
  public void putActivity(Activity activity) {
    // put activity itself
    Serializable activityKey = KEY_PREFIX_ACTIVITY + activity.getId();
    final Element activityElement = new Element(activityKey, activity);
    getCache().put(activityElement);

    // add activity to the list of user
    ArrayList<Activity> activities = null;
    Serializable userKey = KEY_PREFIX_USER_ACTIVITIES + activity.getExecutingUserId();
    Element userActivities = getCache().get(userKey);
    if (userActivities == null) {
      activities = new ArrayList<Activity>();
      userActivities = new Element(userKey, activities);
    } else {
      activities = (ArrayList<Activity>) userActivities.getObjectValue();
    }
    activities.add(activity);
    getCache().put(userActivities);
  }

and here is the corresponding erorr:

Mrz 05, 2016 11:07:40 AM net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask call
Schwerwiegend: Disk Write of u-1 failed: 
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(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.util.ConcurrentModificationException
    at java.util.ArrayList.writeObject(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
    at net.sf.ehcache.Element.writeObject(Element.java:875)
    at sun.reflect.GeneratedMethodAccessor31.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97)
    at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:403)
    ... 10 more

and here more details from ehcache source code:

    private MemoryEfficientByteArrayOutputStream  [More ...] serializeElement(Element element) throws IOException {

         // A ConcurrentModificationException can occur because Java's serialization


         // mechanism is not threadsafe and POJOs are seldom implemented in a threadsafe way.


         // e.g. we are serializing an ArrayList field while another thread somewhere in the application is appending to it.


         try {



             return MemoryEfficientByteArrayOutputStream.serialize(element);



         } catch (ConcurrentModificationException e) {


             throw new 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", e);


         }



  }

Solution

  • You are updating an object while it's been serialized (ehcache try to save it to disk). You should store in a cache only an immutable object.

    In your case, don't try to reuse the ArrayList, create a new one:

    if (userActivities == null) {
          activities = new ArrayList<Activity>();
          userActivities = new Element(userKey, activities);
    } else {
          activities = new ArrayList<Activity>((List) userActivities.getObjectValue());
    }