如何确保主线程仅在子线程启动后继续?

时间:2014-02-06 00:38:03

标签: java multithreading ssh

我正在尝试编写一个程序,首先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();

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

谢谢!

3 个答案:

答案 0 :(得分:1)

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

  

<强> -f

     

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

     

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

     

<强> -N

     

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

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

答案 1 :(得分:0)

首先,JDK5以后不鼓励直接使用线程。精心设计的执行人员将为我们完成工作。如果你有一个较低版本的java或者你想以这种方式做到这一点,那么,这是一个快速的解决方案,

public class Main {

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();
        }
    }
}

}

此致 Lyju

答案 2 :(得分:-1)

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