ebean icon indicating copy to clipboard operation
ebean copied to clipboard

12.8.3 java.util.ConcurrentModificationException: null

Open lbsoft-lwsoft opened this issue 1 year ago • 8 comments

 java.util.ConcurrentModificationException: null
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) ~[na:1.8.0_271]
	at java.util.ArrayList$Itr.next(ArrayList.java:861) ~[na:1.8.0_271]
	at io.ebeaninternal.api.LoadManyRequest.getParentIdList(LoadManyRequest.java:99) ~[ebean-core-12.8.3.jar!/:na]
	at io.ebeaninternal.api.LoadManyRequest.createQuery(LoadManyRequest.java:131) ~[ebean-core-12.8.3.jar!/:na]
	at io.ebeaninternal.server.core.DefaultBeanLoader.loadMany(DefaultBeanLoader.java:44) ~[ebean-core-12.8.3.jar!/:na]
	at io.ebeaninternal.server.core.DefaultServer.loadMany(DefaultServer.java:546) ~[ebean-core-12.8.3.jar!/:na]
	at io.ebeaninternal.server.loadcontext.DLoadManyContext$LoadBuffer.loadMany(DLoadManyContext.java:228) ~[ebean-core-12.8.3.jar!/:na]
	at io.ebean.common.AbstractBeanCollection.lazyLoadCollection(AbstractBeanCollection.java:101) ~[ebean-api-12.8.3.jar!/:na]
	at io.ebean.common.BeanList.init(BeanList.java:139) ~[ebean-api-12.8.3.jar!/:na]
	at io.ebean.common.BeanList.iterator(BeanList.java:335) ~[ebean-api-12.8.3.jar!/:na]
	at java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators.java:1821) ~[na:1.8.0_271]
	at java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408) ~[na:1.8.0_271]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_271]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[na:1.8.0_271]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_271]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_271]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_271]

lbsoft-lwsoft avatar Jun 24 '24 02:06 lbsoft-lwsoft

loadContext.getBatch() Should the copied List be returned?

private LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, boolean lazy, boolean onlyIds, boolean loadCache) {
    super(parentRequest, lazy);
    this.loadContext = loadContext;
    this.batch = loadContext.getBatch();  //Should the copied List be returned?
    this.onlyIds = onlyIds;
    this.loadCache = loadCache;
  }

lbsoft-lwsoft avatar Jun 24 '24 03:06 lbsoft-lwsoft

//Should the copied List be returned?

Generally no. Each loadContext batch is expected to be built by a single thread (via a query that is executed by a single thread). So that means that the batch is not expected to be accessed by another thread during that time that it is being built/mutating. So I'm expecting something interesting to be going on here.

Is there some application caching of entity beans going on? Is the query being used to populate an application cache (and this is done potentially via multiple concurrent threads?).

rbygrave avatar Jun 24 '24 09:06 rbygrave

An entity triggers lazy loading in two threads at the same time. Could this exception be caused? Is lazy loading thread-safe?

lbsoft-lwsoft avatar Jun 24 '24 10:06 lbsoft-lwsoft

Is lazy loading thread-safe?

Yes it is. There is a ReentrantLock that protects the batch lazy loading.

An entity triggers lazy loading in two threads at the same time. Could this exception be caused?

I don't think this is the case in that I think this case is more that there is 1 thread lazy loading and the other thread is still executing the query (still added to the batch load buffer). It could be something along the lines that there is a transaction spanning multiple queries, and that the entity beans are being put into an application cache such that they are accessible by another thread concurrently. Is there anything like that going on?

I presume this is very hard to reproduce / create a failing test case.

As a side point, are you locked into using Java 8? Have you considered getting to Java 11 and getting to the latest version of Ebean?

rbygrave avatar Jun 26 '24 02:06 rbygrave

It is difficult to upgrade the jdk version of the current system. Some of our systems have used the latest version of ebean and I feel that the overall system has improved greatly. I tried to reproduce the problem through test cases but failed. I later solved the problem through other methods, but this still is a dangerous question because it is too implicit

lbsoft-lwsoft avatar Jun 27 '24 09:06 lbsoft-lwsoft

I later solved the problem through other methods

So you don't see the exception anymore? What change did you make?

rbygrave avatar Jun 27 '24 21:06 rbygrave

Info: From several days, I've this issue.

It was with the last Ebean version (and older). It was on Java 17 (and older)

It was stress tests in order to reproduce the problem.

It was exactly this task (https://github.com/ebean-orm/ebean/issues/3425#issuecomment-2186019521)

Is there some application caching of entity beans going on? Is the query being used to populate an application cache (and this is done potentially via multiple concurrent threads?).

From this explanation

Each loadContext batch is expected to be built by a single thread (via a query that is executed by a single thread). So that means that the batch is not expected to be accessed by another thread during that time that it is being built/mutating. So I'm expecting something interesting to be going on here. I have this explanation: Beans with lazy loaded fields are'nt thread safe.

My solution: It is simple query, no update. So I abandon the parent object the moment I create a new thread, I only pass in the id. And with this identifier, I retrieve my child object, which then does not pose a lazy loading problem.

plouf142 avatar Jul 04 '24 13:07 plouf142

I think we should close this ticket for now then. If we need further action we can reopen it etc.

rbygrave avatar Sep 10 '24 11:09 rbygrave

Ok, closing.

rbygrave avatar Feb 26 '25 00:02 rbygrave