简体   繁体   English

从SolverEventListener修改Solution时,Optaplanner ConcurrentModificationException

[英]Optaplanner ConcurrentModificationException when modifying Solution from SolverEventListener

I'm solving a scheduling problem using OptaPlanner solver integrated into a JavaFX GUI that updates on each improvement. 我正在使用集成到JavaFX GUI中的OptaPlanner求解器来解决调度问题,该GUI可以更新每个改进。 Since connecting it to the GUI, this exception frequently happens after the construction heuristic finishes. 由于将其连接到GUI,因此在构造启发式完成后经常会发生此异常。

Exception in thread "Thread-6" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneCollection(FieldAccessingSolutionCloner.java:297)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.process(FieldAccessingSolutionCloner.java:280)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.processQueue(FieldAccessingSolutionCloner.java:273)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneSolution(FieldAccessingSolutionCloner.java:206)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.cloneSolution(FieldAccessingSolutionCloner.java:72)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:142)
    at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:198)
    at org.optaplanner.core.impl.solver.DefaultSolver.runPhases(DefaultSolver.java:217)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:176)
    at no.scheduling.shifts.solver.ShiftOptaPlanner.solve(ShiftOptaPlanner.java:124)
    at application.ScheduleSolver.run(ScheduleSolver.java:69)
    at java.lang.Thread.run(Thread.java:745) 

My GUI code does modify the received solutions as the items it contains have to be displayed to the user in a sorted fashion. 我的GUI代码确实修改了收到的解决方案,因为它包含的项目必须以排序的方式显示给用户。 When I use defensive cloning for solutions provided by the listener's bestSolutionChanged() method, the problem disappears. 当我对侦听器的bestSolutionChanged()方法提供的解决方案使用防御性克隆时,问题就消失了。 Am I doing something wrong here or it might be possible that event listener sometimes gets a wired instance used by OptaPlanner instead of a defensive clone? 我在这里做错了什么,或者事件监听器有时可能会获得OptaPlanner使用的有线实例而不是防御性克隆? I'd really like to avoid the cloning step, as the cloning functionality I currently have available is limited and slow. 我真的想避免克隆步骤,因为我目前可用的克隆功能有限而且速度慢。

EDIT: With some further debugging, I think I was able to pinpoint the issue in the OptaPlanner source (6.4.0 Final) After finishing the construction heuristic phase, the updateBestSolution() method in the BestSolutionRecaller puts the same solution instance in the fireBestSolutionChanged() as it stores in the solverScope : 编辑:对于一些进一步的调试,我想我是能够确定在OptaPlanner源问题(6.4.0决赛)完成建设试探阶段后, updateBestSolution()的方法BestSolutionRecaller提出相同的解决方案的实例在fireBestSolutionChanged()因为它存储在solverScope

 public void updateBestSolution(DefaultSolverScope solverScope, Solution solution, int uninitializedVariableCount) {
        (...)
        solverScope.setBestSolution(solution);
        (...)
        solverEventSupport.fireBestSolutionChanged(solution, uninitializedVariableCount);
    } 

This exactly same instance then goes through cloning in the setWorkingSolutionFromBestSolution at the same time as my GUI thread is sorting the event list in it and exception is thrown as the list of events is iterated in FieldAccessingSolutionClonerRun.cloneCollection() . 这个完全相同的实例然后在setWorkingSolutionFromBestSolution中进行克隆,同时我的GUI线程正在对其中的事件列表进行排序,并且在FieldAccessingSolutionClonerRun.cloneCollection()迭代事件列表时抛出异常。 Guess the solution to the issue would be cloning the solution that goes to fireBestSolutionChanged() ? 猜猜问题的解决方案是克隆fireBestSolutionChanged()的解决方案吗?

Did I stumble upon a subtle bug or I'm doing something wrong? 我偶然发现了一个微妙的错误,或者我做错了什么? Thanks. 谢谢。

Don't do a deep clone (= defensive copy) during bestSolutionEvent. 在bestSolutionEvent期间不要做深度克隆(=防御性拷贝)。 optaplanner-core doesn't do it either because of performance reasons (there's no bug in that code, but planner does do a planning clone (!= deep clone) in BestSolutionRecaller). 由于性能原因,optaplanner-core不会这样做(该代码中没有错误,但计划程序确实在BestSolutionRecaller中进行了规划克隆(!=深度克隆))。

Instead, do a deep clone in your ProblemFactChange s. 相反,在ProblemFactChange进行深度克隆。

A deep clone is different from a planning clone (which is explained in the docs). 深度克隆与计划克隆(在文档中进行了解释)不同。 The 7.0.0.Beta2 docs contain an explanation with this to clarify this further: 7.0.0.Beta2文档包含对此的解释,以进一步阐明:

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM