如何确保只有在子线程启动后主线程才能继续?

Posted

技术标签:

【中文标题】如何确保只有在子线程启动后主线程才能继续?【英文标题】:How to make sure the main thread continues only after child thread has started? 【发布时间】:2014-02-06 00:38:02 【问题描述】:

我正在尝试编写一个程序,首先 ssh'es 到两台不同的机器,然后对它们执行一些 http 请求。这意味着为了能够执行我的 http 请求,ssh 隧道应该运行。

我所做的是我有两个线程,每个线程都运行 ssh 命令到其中一个框:

    Thread thread1 = new Thread(new Runnable()
            public void run()
                try
                    Process p1 = Runtime.getRuntime().exec("ssh -A -L12345:localhost:54321 firsthost.com");
                    p1.waitFor();
                catch (Exception e)
            
        ) ;
        thread1.start();

    Thread thread2 = new Thread(new Runnable()
        public void run()
            try
                Process p2 = Runtime.getRuntime().exec("ssh -A -L12345:localhost:54321 secondhost.com");
                p2.waitFor();
            catch (Exception e)
        
    ) ;
    thread2.start();

现在的问题是,在启动线程后,它们并不总是立即开始运行,这意味着我会在建立连接之前发送我的请求。有没有一种简单的方法(不使用锁或互斥锁)可以确保我只在线程启动后才返回主程序? (我当然不想等待它们结束,因为它们永远不会结束。只需运行第一个命令一次 :) 此外,如果有更好的方法在后台运行进程而不是让这两个单独的线程,那也会很棒!)

谢谢!

【问题讨论】:

【参考方案1】:

尝试添加-f-N 标志,以便在设置端口转发后告诉ssh 自己后台运行。然后您可以在主线程中执行ssh 命令并等待它们退出(即后台本身),然后再继续。

-f

在命令执行之前请求 ssh 进入后台。如果 ssh 将要求输入密码或密码,但用户希望它在后台使用,这很有用。这意味着-n。在远程站点启动 X11 程序的推荐方法是使用 ssh -f host xterm 之类的东西。

如果 ExitOnForwardFailure 配置选项设置为“yes”,则以 -f 启动的客户端将等待所有远程端口转发成功建立,然后再将其置于后台。

-N

不要执行远程命令。这对于仅转发端口很有用(仅限协议版本 2)。

(很遗憾,我目前无法对此进行测试。如果不起作用,请致歉。)

【讨论】:

非常感谢!是的 -f 和 -N 它有效。我现在只需要弄清楚如何避免输入我的密码。 (当我从 shell 执行 ssh 时,它不会以某种方式提示我输入密码,但它会以这种方式提示。)但除此之外,这是一个非常简单的解决方案 :)【参考方案2】:

首先,JDK5 以后不鼓励直接使用线程。包装完好的 Executor 将为我们完成这项工作。如果您有较低版本的 java 或者您仍想以这种方式执行此操作,那么这里有一个快速解决方案,

公共类主

public static void main(String... objs) throws Exception 

    final Process1Thread p1Thread = new Process1Thread();
    final Process2Thread p2Thread = new Process2Thread();

     Thread p1 = new Thread(p1Thread);
     Thread p2 = new Thread(p2Thread);

     p1.start(); p2.start();

     while(true) 
         if(p1Thread.isFinishedCommand() && p2Thread.isFinishedCommand()) 
             //send commands
            System.out.println("sending commands"); 
             break;
            
            


interface FinishedCommand 
    boolean isFinishedCommand();


static class Process1Thread implements Runnable, FinishedCommand 

    private boolean finished = false; 

    @Override
    public boolean isFinishedCommand() 
        synchronized(this) 
            return finished;
        
    

    @Override
    public void run()          
        try 
            final Process p2 = Runtime.getRuntime().exec("dir");

            synchronized(this) 
                finished = true;
                           
            p2.waitFor();
         catch (Exception e) 
            e.printStackTrace();
        

           



static class Process2Thread implements Runnable, FinishedCommand 

    private boolean finished = false; 

    @Override
    public boolean isFinishedCommand() 
        synchronized(this) 
            return finished;
        
    

    @Override
    public void run()          
        try 
            final Process p2 = Runtime.getRuntime().exec("dir");

            synchronized(this) 
                finished = true;
                           
            p2.waitFor();
         catch (Exception e) 
            e.printStackTrace();
        
    

问候 礼州

【讨论】:

【参考方案3】:

您可以使用 thread1.getState() 方法来获取线程的状态。在你可以 thread1.start() 之后,它应该被移动到 RUNNABLE 状态。当 thread1 等待进程完成时,它将处于 BLOCKED 状态。

【讨论】:

这无助于知道ssh何时成功设置端口转发。

以上是关于如何确保只有在子线程启动后主线程才能继续?的主要内容,如果未能解决你的问题,请参考以下文章

java中开启子线程后主线程中传入的变量不变

iOS - 确保在主线程上执行[重复]

Handler系列之使用

QT中UI主窗口如何与子线程相互传递参数

您好,你之前提的关于QThread暂停和继续运行的问题,请问最后是如何解决的?

如何在子线程中访问父线程的空间