运行OptaPlanner混合VRP示例代码触发IllegalStateException求助
问题:OptaPlanner混合VRP代码运行触发IllegalStateException
开发类似项目时参考了OptaPlanner混合VRP实验代码,运行过程中触发IllegalStateException,异常堆栈跟踪如下:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Solving failed. at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.done(SolverAndPersistenceFrame.java:381) at java.desktop/javax.swing.SwingWorker$5.run(SwingWorker.java:750) at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:848) at java.desktop/sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112) at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:858) at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:311) at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:243) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714) at java.base/java.security.AccessController.doPrivileged(AccessController.java:400) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Caused by: java.lang.IllegalStateException: The entity (Visit-18) has a variable (previousStandstill) with value (Visit-25) which has a sourceVariableName variable (nextVisit) with a value (Visit-12) which is not null. Verify the consistency of your input problem for that sourceVariableName variable. at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.insert(SingletonInverseVariableListener.java:74) at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.afterVariableChanged(SingletonInverseVariableListener.java:53) at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.triggerVariableListenersInNotificationQueues(VariableListenerSupport.java:214) at org.optaplanner.core.impl.score.director.AbstractScoreDirector.triggerVariableListeners(AbstractScoreDirector.java:295) at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:37) at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:31) at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:109) at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:38) at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:223) at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:133) at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:117) at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:71) at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99) at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:160) at org.optaplanner.examples.common.business.SolutionBusiness.solve(SolutionBusiness.java:344) at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.doInBackground(SolverAndPersistenceFrame.java:369) at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:304) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:343) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1623)
异常根因分析
核心错误信息表明:实体Visit-18的previousStandstill变量指向Visit-25,但Visit-25的nextVisit变量却指向Visit-12而非Visit-18。这说明路由节点的双向关联变量一致性被破坏,OptaPlanner无法维护这种矛盾的引用关系,从而抛出异常。
排查步骤
- 检查初始解构建逻辑:确保初始化问题时,所有
Visit的previousStandstill与对应Standstill的nextVisit双向匹配。比如若A的previousStandstill是B,则B的nextVisit必须是A,不能出现指向第三方的情况。 - 审查自定义Move实现:如果项目中自定义了路由修改的移动操作,需保证每次修改
previousStandstill时,同步更新对应节点的nextVisit,反之亦然。OptaPlanner内置移动会自动维护关联,但自定义移动容易忽略双向同步。 - 检查自定义VariableListener:若存在自定义的VariableListener,确认其未错误修改关联变量的指向,导致双向引用不一致。
- 启用OptaPlanner断言:在开发环境中添加JVM参数
-ea开启断言,可更早发现变量一致性问题,帮助定位初始化或移动操作中的错误。
内容的提问来源于stack exchange,提问作者Vasavi Bodala
相关产品推荐
相关产品推荐

