如何在Java中安排线程,使其任务彼此依赖?

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个回答

3

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


1
你应该使用Thread.join()来等待子线程完成,这些子线程在完成后应该自动退出。完全没有必要使用Thread.destroy(),也不需要调整线程优先级。

我想我应该澄清一下为什么我不想在我的原始帖子中这样做。 - mavix

0

不要使用原始的Thread集合,而应该将Runnable实例提交给ExecutorService。如果所有线程都在计算某种结果,则可能需要使用Callable<?>ExecutorCompletionService

如果您有一个Runnable的依赖图,则建议使用优秀的Guava库中的ListenableFuture。有关详细信息,请参见ListenableFuture explained wiki文章。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接