从SolverEventListener

时间:2016-09-27 01:31:44

标签: java optaplanner

我正在使用集成到JavaFX GUI中的OptaPlanner解算器来解决调度问题,该GUI解决了每个改进。 由于将其连接到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) 

我的GUI代码会修改收到的解决方案,因为它包含的项目必须以排序的方式显示给用户。 当我使用侦听器bestSolutionChanged()方法提供的解决方案进行防御性克隆时,问题就会消失。 我在这里做错了什么,或者事件监听器有时可能会获得OptaPlanner使用的有线实例而不是防御性克隆? 我真的想避免克隆步骤,因为我目前可用的克隆功能有限而且速度慢。

编辑:通过一些进一步的调试,我想我能够在OptaPlanner源代码中找出问题(6.4.0 Final) 完成构造启发式阶段后,updateBestSolution()中的BestSolutionRecaller方法将fireBestSolutionChanged()中的相同解决方案实例放在solverScope中存储:

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

这个完全相同的实例然后在setWorkingSolutionFromBestSolution中进行克隆,同时我的GUI线程正在对其中的事件列表进行排序,并在FieldAccessingSolutionClonerRun.cloneCollection()中迭代事件列表时抛出异常。 猜猜问题的解决方案是克隆到fireBestSolutionChanged()的解决方案?

我是否偶然发现了一个微妙的错误或者我做错了什么?谢谢。

1 个答案:

答案 0 :(得分:2)

在bestSolutionEvent期间不要进行深度克隆(=防御性复制)。 optaplanner-core之所以这样做是因为性能原因(该代码中没有错误,但规划者确实在BestSolutionRecaller中进行了规划克隆(!=深度克隆))。

相反,请在ProblemFactChange中进行深层克隆。

深度克隆与规划克隆不同(在文档中对此进行了解释)。 7.0.0.Beta2文档包含对此的解释,以进一步阐明:

enter image description here