【问题标题】:How to ensure that a particular thread finishes execution first and the other last?如何确保特定线程先完成执行,另一个最后完成?
【发布时间】:2014-10-10 09:22:00
【问题描述】:

假设有 3 个线程(t1、t2、t3)从主线程产生。我将如何确保特定线程首先完成其执行,而另一个线程最后完成。我并不是要在另一个线程“完成”之后开始一个线程,而是希望确保它们按特定顺序完成

示例代码将非常有帮助。

更准确地说,例如在游戏应用程序中,您可能希望先更改图形,然后再生成声音,然后更新乐谱。

【问题讨论】:

  • 你不能那样做。您能做的最好的事情是创建一个所有线程都完成的“检查点”。参考文献CyclicBarrierCountDownLatch.
  • 为什么?这完全取决于它们需要多长时间以及它们之间是否存在类似信号量的交互。如果没有,则完成顺序是不确定的。
  • 我突然想问为什么你想要一个有保证的线程终止顺序。没有更多细节,它开始看起来越来越像XY problem...
  • 请与我们分享您的实际问题。您不会(即不应)生成一个线程只是为了更新游戏中的分数一次...
  • 你可以使用wait() notify()

标签: java multithreading concurrency


【解决方案1】:

您可以使用wait()notify()。它是一种机制,我们可以通过它在线程之间发送信号。

wait()导致线程在临界区暂停。暂停时线程释放它的锁。它必须在同步块或方法中调用。

notify() 将向等待同一对象的线程之一发送信号。它唤醒已调用 notify() 的线程。

这是一个包含两个功能的示例:显示和声音。显示将在声音之前完成:

(您也可以添加第三个(分数)。)

class shared
{
    synchronized void disp()
    {
        System.out.println("Display thread complete");

        notify();
    }
    synchronized void play_s()
    {
        try
        {
            wait();
        }
        catch(InterruptedException ie)
        {
            ie.printStackTrace();
        }
        System.out.println("Sound thread complete");
    }


}
class display extends Thread
{
    shared sh;
    public display(shared sh,String str)
    {
        super(str);
        this.sh=sh;
        start();
    }
    public void run()
    {
        sh.disp();
    }

}

class sound extends Thread

{
    shared sh;
    public sound(shared sh,String str)
    {
        super(str);
        this.sh=sh;
        start();
    }
    public void run()
    {
        sh.play_s();
    }

}

public class sync {

    public static void main(String agrs[])
    {
        shared sh=new shared();
        display d=new display(sh,"one");
        sound s=new sound(sh,"two");

    }

}

【讨论】:

  • 呃,你真的试过这个吗?在我的系统上,显示线程完成得如此之快,以至于声音线程永远被卡住,等待永远不会出现的通知......
  • 呃!很抱歉..让我检查一下..代码应该可以工作..我编辑了我的代码,对于这个答案,也许我忘记了一些东西..如果某处有小错误,您可以编辑答案.. :)
  • Nivedita:老实说,它可能需要大修才能正常工作,更不用说添加第三个线程不是微不足道的。将对象添加到 Java 中是有原因的...
  • 我同意 thkala,此代码需要大修。特别是,wait 被滥用;它不应该用于等到另一个线程通知这个线程。相反,wait 应该等到条件为真或对象达到所需状态。
  • 在这种情况下,我们是否可以使用布尔变量来确定是否运行声音和其他线程?我应该编辑答案吗?还是删除它?
【解决方案2】:

“更准确地说,在游戏应用程序中,您可能希望先更改图形,然后再生成声音,然后更新乐谱。”

这需要顺序执行外部可见的活动。图形更新必须发生在事件处理线程中,这似乎是对活动进行排序的明显位置。

我会为每个活动分离出任何计算密集型或其他耗时的准备工作,并将其委托给一个线程或线程池,而不用担心顺序。使用例如invokeLater 在计算完成时通知事件处理线程。在事件处理线程中,跟踪做某事的条件,例如改变分数。当所有条件都满足时,包括所有先决条件的完成,执行操作。

【讨论】:

  • 我不确定 OP 正在开发一款游戏 - 如果是,那么他们正在做一些非常奇怪的事情。他们应该专注于正确地并行化各种流程和数据流,使用并发基础设施来处理任何相互依赖关系。为什么要担心线程终止
【解决方案3】:

您的问题没有多大意义,因为线程的完成对应用程序的状态没有影响,因此完成顺序也完全不相关。您实际尝试实现的目标很可能需要不同的解决方案。

您的示例说明了这一点:“假设在游戏应用程序中,您希望首先更改图形,然后您希望生成声音,然后更新分数”。在这里,您正在描述一个接一个地执行的操作,这与您的陈述“我的意思不是在另一个线程“完成”之后开始一个线程”完全矛盾。

您可能的意思是您想要加载或计算资源,例如图形和声音,同时但希望按顺序渲染它们。因此,关键是将渲染中的加载/计算拆分为两个相关的任务。然后,虽然图形渲染任务仅取决于图形创建的完成,但声音渲染取决于声音数据的创建和图形渲染的完成,以建立您想要的顺序。所以不是声音线程的结束依赖于图形线程的结束,而是声音渲染的开始依赖于图形渲染的结束。

有很多方法可以实现这些东西,但考虑到你的问题是多么抽象,它太宽泛了。

但是,关于您的原始问题,有Thread.join()。当线程T2 执行的代码在线程T1 上调用该方法时,它将等待T1 的终止,因此线程T2 不会在T1 之前终止。但是,如前所述,在T2 的末尾放置这样的等待没有多大意义,因为线程的完成顺序毫无意义。您必须将它放在之前依赖操作的开头。

【讨论】:

  • 关于矛盾的部分:“开始一个线程”意味着启动一个不同于重复任务的线程。如果我提到游戏应用程序,您应该自己理解它。我确实理解多线程的意义,但为了学习和了解事物在幕后的实际工作方式,人们提出了某些问题。顺便说一句,感谢您的解决方案,我已经想到了。
  • @rsb:你没有问“事情实际上是如何运作的”的问题,那么你评论的意义何在?术语开始结束总是被定义为与它们之间的活动的关系。订购整理是没有意义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-12-04
  • 2019-10-04
相关资源
最近更新 更多