Optaplanner 7.9.0和添加多线程:相同的planningId异常

时间:2018-07-30 15:47:39

标签: optaplanner

我有一个optaplanner项目工作了一段时间,该项目正在使用所有用Java编写的各种评分属性将作业分配给工人列表。我对它的工作方式感到满意,因此我决定从7.7.0更新到7.9.0,并打开新的多线程选项,看看它是否能更快地工作。但是,我现在收到以下错误:

线程“ Thread-8”中的异常java.lang.IllegalStateException:具有moveThreadIndex(0)的移动线程引发了异常。在父线程中中继到这里。 原因:java.lang.IllegalArgumentException:无法查找externalObject(... Worker @ 72d2327a)。 也许给类(Worker类)一个PlanningId注释,或者更改PlanningSolution注释的LookUpStrategyType,或者不依赖依赖于ScoreDirector.lookUpWorkingObject()的功能。

所以我尝试将@PlanningId添加到worker类的唯一标识符中,然后得到:

线程“ Thread-7”中的异常java.lang.IllegalStateException:workingObjects(Worker @ 4438b624,Worker @ 4438b624)具有相同的planningId((类Worker,50))。工作对象必须是唯一的。

...但是看起来它正在将Worker对象与其自身进行比较,所以它的ID相同吗??

也许这取决于我的java代码中的assign / unassign方法,但我不知道此问题来自何处,有人有任何想法吗?

编辑: 因此,在@ n1ck的大量帮助下,我可以更改@PlanningSolution类中的方法,该方法每次都返回具有相同值的新实例来返回Worker列表。这会将错误更改为:'...... workingObjects(Worker @ 1eba2b4d,Worker @ 67a7ef08)具有相同的planningId ...',因此不再比较相同的实例,但似乎是将其与先前调用的实例进行比较。但是,这至少可以确认返回的每个列表都没有重复项。因此,然后我将计划ID更改为一个新的(Long)字段,其值始终从创建的最后一个实例开始增加,即第一次调用的工作ID为1-10,下一次调用的ID为11-20,依此类推。这完全绕过了错误,但是现在没有任何东西分配给工人。它进行初始设置并分配空值,然后停止直到达到求解器的时间限制。我仍然认为这是我尚未解决的问题,但错误可能有点像是鲱鱼,但是正如我所看到的那样,按照要求的完整堆栈跟踪信息是:

线程“ Thread-10”中的异常java.lang.IllegalStateException:workObjects(Worker @ 42094cc1,Worker @ 647a1c5c)具有相同的planningId((Worker类,50))。工作对象必须是唯一的。     在org.optaplanner.core.impl.domain.lookup.PlanningIdLookUpStrategy.addWorkingObject(PlanningIdLookUpStrategy.java:40)     在org.optaplanner.core.impl.domain.lookup.LookUpManager.addWorkingObject(LookUpManager.java:49)     在org.optaplanner.core.impl.domain.lookup.LookUpManager.resetWorkingObjects(LookUpManager.java:43)     在org.optaplanner.core.impl.score.director.AbstractScoreDirector.setWorkingSolution(AbstractScoreDirector.java:167)     在org.optaplanner.core.impl.score.director.incremental.IncrementalScoreDirector.setWorkingSolution(IncrementalScoreDirector.java:62)处     在org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:230)处     在org.optaplanner.core.impl.solver.AbstractSolver.solvingStarted(AbstractSolver.java:75)     在org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:210)     在org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:190)     在SolverThread.run(SolverThread.java:86)

编辑:@PlanningSolution类,根据要求:

package code.test.scheduler;

import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
import org.optaplanner.core.api.domain.solution.PlanningScore;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
import org.optaplanner.persistence.xstream.api.score.buildin.hardmediumsoft.HardMediumSoftScoreXStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamConverter;

@PlanningSolution
public class Planner
{       
@ProblemFactCollectionProperty
private java.util.List<Worker> _workerList;
@ValueRangeProvider(id="workerRange")
@ProblemFactCollectionProperty
public java.util.List<Worker> getWorkerList() {
    return _workerList;
}
public void setWorkerList(java.util.List<Worker> newWorkerList) {
    _workerList = newWorkerList;
}
public int getWorkerListSize() {
    return _workerList.size();
}

@ProblemFactCollectionProperty
private int[][] _travelTimes;
@ValueRangeProvider(id="travelTimes")
@ProblemFactCollectionProperty
public int[][] getTravelTimes() {
    return _travelTimes;
}
public void setTravelTimes(int[][] newTravelTimes) {
    _travelTimes = newTravelTimes;
}

@PlanningEntityCollectionProperty
private java.util.List<Job> _jobList;
public java.util.List<Job> getJobList() {
    return _jobList;        
}
public void setJobList(java.util.List<Job> newJobList) {
    _jobList = newJobList;
}

@XStreamConverter(HardMediumSoftScoreXStreamConverter.class)
private HardMediumSoftScore _score;

@PlanningScore
public HardMediumSoftScore getScore() {
    return _score;
}

public void setScore(HardMediumSoftScore score) {
    _score = score;     
}
}

1 个答案:

答案 0 :(得分:2)

我认为您的PlanningEntityCollection中有一些重复的实体。您确定此列表中的所有Worker对象都是唯一的(例如,不是同一实例)?

我故意在我的实体集合中复制了一个实体,并得到了相同的错误。

编辑:事实证明,问题是在字段和getter上方声明了@ProblemFactCollectionProperty注释。仅应在一个或另一个之上声明它。结合使用@PlanningId批注在字段和getter上方声明它,将导致“工作对象必须唯一”错误。