3

这是我在学校的操作系统课上学习线程(理论上,呵呵)后第一次尝试多线程,我认为我做我想做的事情的方式是不好的做法/草率。

我通过为设置运行该算法的游戏的每个分支生成一个单独的线程来并行化一个极小极大算法。这其中的调度部分有点棘手。随着算法迭代地加深,我希望所有线程的深度保持一致。

所以,首先我有一个主线程,它为游戏中的每个可用动作生成一个子线程:

    public void run(){
        // initializes all the threads
        for (AlphaBetaMultiThread t : threadList) {
            t.start();
        }
        try { //This won't ever happen; the subthreads run forever
            evals = 0;
            for (AlphaBetaMultiThread t : threadList) {
                t.join();
                evals += t.evals;
            }
        } catch (Exception e) {
            System.out.println("Error joining threads: " + e);
        }
    }

线程将自己传递给构造函数,以便每个子线程都可以访问主线程的 maxDepth 属性和 signalDepth 方法:

    public synchronized void signalDepth(){
        signals++;
        if (signals % threadList.length() == 0){
            if (verbose)
                System.out.println(toString());
            depth++;
        }
    }

最后,这是子线程评估过程。每当它领先于其他线程时,它就会降低自己的优先级,然后让步,直到所有子线程都发出信号。

public void run() {
    startTime = System.currentTimeMillis();
    while(true){
        if (depth >= master.maxDepth) {
            this.setPriority(4);
            this.yield();
            break;
        } else {
            this.setPriority(5);
        }
        eval = -1*alphabeta(0, infHolder.MIN, infHolder.MAX);
        manager.signalDepth();
        depth += 1;
    }
}

除了我的实现现在似乎根本不起作用(仍在试图找出原因)这一事实之外,我真的觉得我正在做的事情不是标准的做事方式。我的直觉是,可能有各种各样的内置多线程库可以让我的生活更轻松,但我真的不知道我在寻找什么。

哦,我还收到警告说 Thread.destroy() 已被弃用(这就是我打算在计算机播放器最终播放它之后销毁所有东西的方式)。

我想我的问题是:我应该用什么来管理我的子线程?

编辑:哦,如果我遗漏了与我的问题相关的内容,请随时查看我在 github 上的完整代码:https ://github.com/cowpig/MagneticCave 相关文件是 GameThread 和 AlphaBetaMultiThread。我为我的无知道歉!

另一个编辑:我希望线程永远迭代加深,直到 gamePlayer 对象(创建主线程的那个)决定是时候选择一个动作了——在这个时候它将访问动作列表并找到最高的一个评估。这意味着 .join() 将不起作用,除非我为每个深度迭代创建一组新的线程,但是那将需要更多的开销(我认为)所以我真的不想这样做。

4

4 回答 4

3

你的直觉是正确的。Java 5 引入了许多有用的并发构造。您可能要特别研究的一个是CyclicBarrier。它是一种同步辅助工具,允许多个线程相互等待以达到共同的障碍点(在您的情况下,这将是主深度)。

于 2012-11-26T03:02:24.457 回答
1

您应该使用 Thread.join() 等待子线程,完成后应该退出。根本不需要 Thread.destroy() ,也不需要摆弄优先级。

于 2012-11-26T02:54:23.217 回答
0

而不是为此使用原始实例的集合Thread,您应该将Runnable实例提交到ExecutorService. 如果您的所有线程都在计算某种结果,您可能希望使用Callable<?>and ExecutorCompletionService

如果您有Runnables 的依赖关系图,我建议您使用ListenableFuture优秀的 Guava 库。有关详细信息,请参阅ListenableFuture解释的wiki 文章。

于 2012-11-26T03:03:03.600 回答
0

如果数据流图表示适合您的任务,您可以使用我的数据流库df4j

于 2012-11-26T05:59:39.290 回答