**财政。我的项目是关于推荐的文章列表,每一篇文章都有自己的规则,所以我使用AsyncTaskExecutor这个工具类来并发查询不同的文章,而现在,有些规则是特殊的,所以我把它们分成两部分。下面是我的代码:我使用springboot + mybatis来做**
@Bean
public AsyncTaskExecutor dataTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(16);
executor.setThreadNamePrefix("data_task_executor-");
return executor;
}这里我初始化了AsyncTaskExecutor类,接下来是并发查询的部分代码.
// here i get different rule list
List<Rule> ruleList = JSON.parseArray(scene.getRules(), Rule.class);
Iterator<Rule> ruleIterator = ruleList.iterator();
CountDownLatch latch1 = new CountDownLatch(ruleList.size());
while (ruleIterator.hasNext()) {
Rule ruleNext = ruleIterator.next();
// unAsyncScenes is a array,this rule query in here
if (Arrays.binarySearch(unAsyncScenes, ruleNext.getSource()) >= 0) {
dataTaskExecutor.execute(() -> {
try {
searchIDSByRule(idWithRtsMap, articleReferralList, sceneId, feedSum, userId, isNewUserByHistory, discussHistoryList, discussList, graphHistorys, ruleNext);
//Record browsing history
graphHistorys.addAll(idWithRtsMap.keySet());
} catch (Exception e) {
log.warn("子规则查图失败", e);
} finally {
latch1.countDown();
}
});
//Query deleted
ruleIterator.remove();
} else {
latch1.countDown();
}
}
try {
latch1.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error("多线等待异常:", e);
}
//deal with Duplicate article
Set<Long> articleSet = new HashSet();
articleReferralList.forEach(article -> articleSet.add(article));
if (articleReferralList.size() != articleSet.size()) {
log.warn("出现了重复的文章");
articleReferralList.clear();
articleReferralList.addAll(articleSet);
}
final CountDownLatch latch = new CountDownLatch(ruleList.size());
for (Rule rule : ruleList) {
// second concurrent query(query for other article)
dataTaskExecutor.execute(() -> {
try { *****// here hava error!!!!!!!!!!!!*****
searchIDSByRule(idWithRtsMap, articleReferralList, sceneId, feedSum, userId, isNewUserByHistory, discussHistoryList, discussList, graphHistorys, rule);
} catch (Exception e) {
log.warn("子规则查图失败", e);
} finally {
latch.countDown();
}
});
}
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error("多线等待异常:", e);
}这都是查询代码,但我运行了这段代码,有时会出现如下错误:
org.apache.ibatis.exceptions.PersistenceException: \
### Error querying database. Cause: java.util.ConcurrentModificationException\
### Cause: java.util.ConcurrentModificationException\
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) ~[mybatis-spring-1.3.1.jar!\/:1.3.1]\
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) ~[mybatis-spring-1.3.1.jar!\/:1.3.1]\
at com.sun.proxy.$Proxy91.selectList(Unknown Source) ~[?:?]\
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) ~[mybatis-spring-1.3.1.jar!\/:1.3.1]\
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at com.sun.proxy.$Proxy131.searchBySigAndExample(Unknown Source) ~[?:?]\
at com.coffee.ref.service.impl.ReferralServiceImpl.searchIDSByRule(ReferralServiceImpl.java:842) ~[classes!\/:0.0.1]\
at com.coffee.ref.service.impl.ReferralServiceImpl.lambda$findArticleIDSByRule$7(ReferralServiceImpl.java:625) ~[classes!\/:0.0.1]\
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_212]\
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_212]\
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_212]\
Caused by: org.apache.ibatis.exceptions.PersistenceException: \
### Error querying database. Cause: java.util.ConcurrentModificationException\
### Cause: java.util.ConcurrentModificationException\
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source) ~[?:?]\
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]\
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]\
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433) ~[mybatis-spring-1.3.1.jar!\/:1.3.1]\
... 11 more\
Caused by: java.util.ConcurrentModificationException\
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[?:1.8.0_212]\
at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[?:1.8.0_212]\
at org.apache.ibatis.scripting.xmltags.ForEachSqlNode.apply(ForEachSqlNode.java:62) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:83) ~[pagehelper-5.1.2.jar!\/:?]\
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at com.sun.proxy.$Proxy188.query(Unknown Source) ~[?:?]\
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.5.jar!\/:3.4.5]\
at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source) ~[?:?]\
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]\
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]\
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433) ~[mybatis-spring-1.3.1.jar!\/:1.3.1]\
... 11 more\"}"]报告错误的地方在上面。我不明白为什么,mybatis应该是线程安全的。
发布于 2019-10-23 02:54:07
官方文件显示它是线程安全的。
发布于 2019-10-23 08:52:51
SqlSessionTemplate本身是线程安全的。问题在于你的代码。
异常显示错误发生在foreach元素中。请注意堆栈跟踪的以下部分:
Caused by: java.util.ConcurrentModificationException\
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[?:1.8.0_212]\
at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[?:1.8.0_212]\
at org.apache.ibatis.scripting.xmltags.ForEachSqlNode.apply(ForEachSqlNode.java:62) ~[mybatis-3.4.5.jar!\/:3.4.5]\那么这里发生了什么?在映射器中,通过迭代某些集合来动态构建SQL。此集合由另一个线程并发修改。集合上的迭代器已内置检查集合是否被修改,此检查表明存在问题。
为了解决这个问题,您需要同步对多个线程中使用的集合的访问,以便当您使用集合来基于它查询某些数据时,这是原子性的,并且在查询生成过程中不会发生任何修改。
造成这种情况的一个可能原因是,没有分析此await的结果:
latch1.await(10, TimeUnit.SECONDS);如果处理时间超过10秒,则第二部分开始执行,而查询所基于的数据仍在修改。这可能是因为要做的工作量取决于数据。
您需要检查此await的结果,并且在该过程的第一部分中的所有任务完成之前不要继续处理。
https://stackoverflow.com/questions/58514781
复制相似问题