1、使用线程并发解决从一些初始状态寻找到达目标状态的转换序列,这样包含了一个初始位置,一个目标位置,为了确定起点与目标的有效移动,还包含一个规则集。
2、定义迷题类
public interface Puzzle
{
PinitialPosition();
booleanisGoal(P position);
Set
P move(Pposition,M move);
}
3、定义位置节点类
public class Node
{
final P pos;
final M move;
finalNode
prev;
Node(P pos,Mmove,Node
prev){...}
List
List
for(Node
n=this;n.move!=null;n=n.prev)
solution.add(0,n.move);
return solution;
}
}
4、ConcurrentPuzzleSolver使用内部类solverTask,solveTask同时扩展了Node并实现了Runnable。大多数工作是在run中完成的:首先计算下一步可能的位置集,从中除去已经到达的位置,然后判断是否已经成功地完成,最后把尚未搜索的位置提交给Executor。ConcurrentMap使用了puIfAbsent可以原子化地增加一个位置,当且仅当这个位置先前是不存在的.ConcurrentPuzzleSolver使用内部线程池的工作队列保留搜索的状态,而不是调用栈.
每个任务首先向闭锁请求方案,如果方案被发现,即isSet为真则停止,ValueLatch中的getValue阻塞到有纯种设置了Value为止.
第一个发现解法的线程会关闭Executor,以拒绝接受新的任务.为了避免处理RejectedExecutionException,可以设置一个拒绝执行处理器,让这丢弃已经提交的任务.
public classConcurrentPuzzleSolver
{
privatefinal Puzzle
puzzule;
privatefinal ExecutorService exec;
privatefinal ConcurrentMap
seen;
finalValueLatch
...
publicList
try{
P p=puzzle.initialPostion();
exec.execute(newTask(p,null,null));
//阻塞,直到发现一个方案
Node
solnNode=solution.getValue();
return (solnNode==null)?null:solnNode.asMoveList();
}
finally{
exec.shutdown();
}
}
protectedRunnable newTask(P p,M m,Node
n){
returnnew SolverTask(p,m,n);
}
classSolverTask extends Node
implements Runnable{
...
public void run(){
if (solution.isSet()||seen.putIfAbsent(pos,true)!=null)
return;
if (puzzle.isGoal(pos)) solution.setValue(this);
else
for (M m:puzzle.legalMoves(pos))
exec.execut(newTask(puzzle.move(pos,m),m,this));
}
}
}
@ThreadSafe
publicclass ValueLatch
@GuardedBy("this") private T value=null;
privatefinal CountDownLatch done=new CountDownLatch(1);
publicboolean isSet(){
return (done.getCount()==0);
}
publicsynchronized void setValue(){
if (!isSet()){
value=newValue;
done.countDown();
}
}
public TgetValue() throws InterruptedException{
done.await();
synchronized(this){returnvalue;}
}
}