Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 等待多线程事件后执行,同时保持已启动进程运行_Java_Multithreading - Fatal编程技术网

Java 等待多线程事件后执行,同时保持已启动进程运行

Java 等待多线程事件后执行,同时保持已启动进程运行,java,multithreading,Java,Multithreading,基本上,我启动了多个线程,这些线程再次启动了一个应该被监控的长时间运行的进程。在本例中,“长时间”运行的进程是简单的ping调用。IpListener有责任在进程结束或失败时触发事件 现在是有趣的部分:每当在控制台输出中发现ip时,都会触发onIpFound方法。我想做的是等待所有线程第一次找到IP,然后继续执行main方法。但是,启动的进程应该继续运行,并最终触发前面提到的onProcessEnd和onProcessFailure事件。您是否有任何提示来实现此行为(以合理的方式) 以下是小示例

基本上,我启动了多个线程,这些线程再次启动了一个应该被监控的长时间运行的进程。在本例中,“长时间”运行的进程是简单的ping调用。IpListener有责任在进程结束或失败时触发事件

现在是有趣的部分:每当在控制台输出中发现ip时,都会触发onIpFound方法。我想做的是等待所有线程第一次找到IP,然后继续执行main方法。但是,启动的进程应该继续运行,并最终触发前面提到的onProcessEnd和onProcessFailure事件。您是否有任何提示来实现此行为(以合理的方式)

以下是小示例应用程序的各个部分,以帮助您更好地理解:

ReaderTest.java

package com.test;
public class ReaderTest {
    public static void main(String[] args) {
        IpReader ipReader = new IpReader("stackoverflow.com");
        ipReader.setListener(new SimpleIpListener());
        new Thread(ipReader).start();

        IpReader ipReader2 = new IpReader("stackexchange.com");
        ipReader2.setListener(new SimpleIpListener());
        new Thread(ipReader2).start();

        // TODO: start next step as soon as both ips are known
    }
}
IpReader.java

package com.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IpReader implements Runnable {

    private IpListener ipListener = null;
    private String hostName;

    public IpReader(String hostName) {
        this.hostName = hostName;
    }

    public interface IpListener {
        public void onIpFound(String ip);

        public void onProcessEnd(String string);

        public void onProcessFailure(String string);
    }

    public void setListener(IpListener ipListener) {
        this.ipListener = ipListener;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        ProcessBuilder pb = new ProcessBuilder().command("cmd", "/c", "ping", "-n", "10", hostName);
        pb.redirectErrorStream(true);

        Process process = null;
        try {
            try {
                process = pb.start();

                String line = null;
                // print stream
                BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
                while ((line = br.readLine()) != null) {

                    Pattern p = Pattern.compile("(?:[0-9]{1,3}\\.){3}[0-9]{1,3}");
                    Matcher m = p.matcher(line);

                    if (m.find()) {
                        // IPv4 found
                        if (ipListener != null) {
                            ipListener.onIpFound(m.group(0));
                        }
                    }
                }

                process.waitFor();
                if (ipListener != null)
                    ipListener.onProcessEnd("Process END");
            } finally {
                if (process != null)
                    process.destroy();
            }

        } catch (InterruptedException | IOException e) {
            if (ipListener != null)
                ipListener.onProcessFailure("Process failure");
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}
SimpleIpListener.java

package com.test;
import com.test.IpReader.IpListener;

public class SimpleIpListener implements IpListener {

    private boolean ipFound = false;

    @Override
    public void onIpFound(String ip) {
        if (!ipFound)
            System.out.println("IP " + ip + " found.");
        ipFound = true;
    }

    @Override
    public void onProcessEnd(String string) {
        System.out.println("Process ended.");
    }

    @Override
    public void onProcessFailure(String string) {
        System.out.println("Process failure");
    }

}

一种方法是引入一个在IpReader(或您的侦听器)线程之间共享的对象,当它们找到ip时,都可以更新该对象

例如,介绍这个简单的类:

class WaitTask {
    private int numberRead;

    public int getNumberRead(){
        return numberRead;
    } 

    public void increment(){
        numberRead++;
    }
}
现在在您的主要方法中:

public static void main(String[] args) {
    // create an instance of that class, which keeps track of how many threads found an ip
    final WaitTask waitTask = new WaitTask();
    // create an int to know how many we are expecting
    final int totalThreadsRunning = 2;

    IpReader ipReader = new IpReader("stackoverflow.com");
    ipReader.setListener(new SimpleIpListener());

    // pass our object to the thread
    ipReader.setWaitTask(waitTask);
    new Thread(ipReader).start();

    IpReader ipReader2 = new IpReader("stackexchange.com");
    ipReader2.setListener(new SimpleIpListener());

    // pass our object to the thread
    ipReader2.setWaitTask(waitTask);
    new Thread(ipReader2).start();

    // Now wait until the wait task object is safe to be accessed

    synchronized(waitTask){

        // once we know it's safe let's check if we read as many responses as required

        while(waitTask.getNumberRead() < totalThreadsRunning )
        {
            // instead of looping forever wait for a thread to notify that 
            // the wait task number read was changed

            waitTask.wait();
            // the wait blocks execution and waits until waitTask was             
            // changed, after that the while loop condition gets evaluated
            // once we read as many as required we exit the loop
        }
    }

    // when we reach here all threads have finished so do anything you want
}
使用“原子变量”存储ip地址。这些可以由ping线程设置,并由主线程检查。在主线程中,在“条件变量”上暂停。当ping线程收到ip地址时,它们将唤醒主线程。

这将要做的是,设置一个变量,ping线程可以发布数据,主线程也可以读取。此外,主线程将在条件变量上停止(并且不消耗处理器时间),但在发现新ip时唤醒。然后它将检查两个ip引用是否都已填充

在全球范围内定义这些:

AtomicReference ip1 = new AtomicReference(new String(""));
AtomicReference ip2 = new AtomicReference(new String(""));
final Lock lock = new ReentrantLock();
final Condition wakeup  = lock.newCondition(); 
然后在主线程中

while(ip1.get().length == 0 && ip2.get().length == 0)
{
wakeup.await();
}
在IpReader定义中:

 private String hostName;
 private AtomicReference ipstring;

public IpReader(String hostName,AtomicReference outputstring) {
    this.hostName = hostName;
    this.ipstring = outputstring;
}
最后

@Override
public void onIpFound(String ip, AtomicReference ref) {
    if (!ipFound)
        System.out.println("IP " + ip + " found.");
    ipFound = true;
    ref.set(ip);
    wakeup.signal();
}
@Override
public void onIpFound(String ip, AtomicReference ref) {
    if (!ipFound)
        System.out.println("IP " + ip + " found.");
    ipFound = true;
    ref.set(ip);
    wakeup.signal();
}