Java 多线程ArrayList迭代

Java 多线程ArrayList迭代,java,multithreading,arraylist,javafx-8,Java,Multithreading,Arraylist,Javafx 8,欢迎 我正在用Java(JavaFX8)编写一个简单的服务器监控应用程序。当前的实现能够逐个ping目标机器,并将它们绘制到JavaFX折线图上。每台机器都是一个“目标”对象,保存在ArrayList(可观察)中。我的问题是“一个接一个”的部分。ping目标的代码是返回ping的可调用代码。一、 不知何故,我需要多线程处理这个过程,这样我一次至少可以ping四个目标。过去的尝试导致了一些怪癖,比如四个线程同时ping同一个目标,导致了毫无意义的处理器冗余。这是我当前的循环 public void

欢迎

我正在用Java(JavaFX8)编写一个简单的服务器监控应用程序。当前的实现能够逐个ping目标机器,并将它们绘制到JavaFX折线图上。每台机器都是一个“目标”对象,保存在ArrayList(可观察)中。我的问题是“一个接一个”的部分。ping目标的代码是返回ping的可调用代码。一、 不知何故,我需要多线程处理这个过程,这样我一次至少可以ping四个目标。过去的尝试导致了一些怪癖,比如四个线程同时ping同一个目标,导致了毫无意义的处理器冗余。这是我当前的循环

public void beginPing() {
    ExecutorService exec = Executors.newCachedThreadPool();

    Runnable r = new Runnable() {
        @Override
        public void run() {
            while (true) {
                for (Target t : targets) {
                    String ping = null;
                    if (t.flagsProperty().get().contains("A")) {
                        try {
                            Callable c = new Pinger(t);
                            ping = c.call().toString();
                            switch (ping) {
                                case "TIME_OUT":
                                    for (XYChart.Series s : lineChart.getData()) {
                                        if (s.getName().equals(t.nameProperty().get())) {
                                            addToChart(s, cycle, 00.00);
                                        }
                                    }
                                    t.setStatus("TIME OUT");
                                    t.setLastrtt("TIME_OUT");
                                    t.setTimeouts(t.timeoutsProperty().get() + 1);
                                    logUtil.log(LogUtil.INFO, t.nameProperty().get() + " - timed out!");
                                    break;
                                case "UNKNOWN_HOST":
                                    t.setStatus("ERROR");
                                    t.setLastrtt("UNKNOWN HOST");
                                    logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - unknown host!");
                                    break;
                                case "UNREACHABLE":
                                    t.setStatus("ERROR");
                                    t.setLastrtt("UNREACHABLE HOST");
                                    logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - is unreachable!");
                                    break;
                                default:
                                    t.setLastrtt(ping);
                                    t.setStatus("ACTIVE");
                                    for (XYChart.Series s : lineChart.getData()) {
                                        if (s.getName().equals(t.nameProperty().get())) {
                                            addToChart(s, cycle, Double.valueOf(ping));
                                        }
                                    }
                                    break;
                            }
                        } catch (Exception e) {
                            logUtil.log(LogUtil.CRITICAL, e.getMessage() + ", "+ e.getCause());
                            e.printStackTrace();
                        }
                    }
                }
                cycle++;
                rangeChart(cycle);
                updateInfo();
            }
        }
    };
    exec.execute(r);
} 

我的印象是,您像普通类一样滥用了可调用类Pinger,尽管它只是一个不实现任何多线程服务的接口。 您想做的事情应该更像这样:

//init
Future<String> futures = new Future[targets.length];
String results = new String[targets.length];
ExecutorService service =  Executors.newCachedThreadPool();

//start Threads
for (int i = 0; i<targets.length; i++){      
    Pinger pinger= new Pinger(targets[i]);
    future[i] = service.submit(pinger);
}

//wait for Threads to finish and get results
for(int i = 0; i<futures.length; i++)
    results[i] = futures[i].get()
public class Pinger implements Callable<String>{
    Pinger(Target target){ ... }
    public String call(){ ... }
}
//初始化
期货=新的期货[目标.长度];
字符串结果=新字符串[targets.length];
ExecutorService=Executors.newCachedThreadPool();
//开始线程

对于(inti=0;iSo),这里是当前的工作实现

public void beginPing() {
    safeTargets = new ArrayList<>(); //thread-safe collection
    for (Target t : targets) {
        safeTargets.add(t);
    }
    safeTargets = Collections.synchronizedList(targets);

    exec = Executors.newCachedThreadPool();

    for (int i = 0; i < 4; i++) { //number of threads
        exec.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    for (Target t : safeTargets) {
                        String ping = null;
                        if (t.isActive() && !t.isIsBeingPinged()) { //checks if target is already being pinged by another thread and if it flagged as active and wishes to be pinged.
                            t.setIsBeingPinged(true);
                            t.setPinged(t.getPinged() + 1); //just to see how many times it has been pinged
                            t.setStatus("PINGING");
                            try {
                                Callable c = new Pinger(t);
                                ping = c.call().toString();
                                switch (ping) {
                                    case "TIME_OUT":
                                        t.setStatus("TIME OUT");
                                        t.setLastrtt("TIME_OUT");
                                        t.setTimeouts(t.timeoutsProperty().get() + 1);
                                        logUtil.log(LogUtil.INFO, t.nameProperty().get() + " - timed out!");
                                        t.setIsBeingPinged(false);
                                        break;
                                    case "UNKNOWN_HOST":
                                        t.setStatus("ERROR");
                                        t.setLastrtt("UNKNOWN HOST");
                                        logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - unknown host!");
                                        t.setIsBeingPinged(false);
                                        break;
                                    case "UNREACHABLE":
                                        t.setStatus("ERROR");
                                        t.setLastrtt("UNREACHABLE HOST");
                                        logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - is unreachable!");
                                        t.setIsBeingPinged(false);
                                        break;
                                    default:
                                        t.setLastrtt(ping);
                                        t.setStatus("ACTIVE");
                                        t.setIsBeingPinged(false);
                                        break;
                                }
                                System.out.println("C=" + t.getPinged() + " - " + t.nameProperty().get());
                            } catch (Exception e) {
                                logUtil.log(LogUtil.CRITICAL, e.getMessage() + ", " + e.getCause());
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        });
    }
}
public void beginPing(){
safeTargets=new ArrayList();//线程安全集合
对于(目标t:目标){
安全目标。添加(t);
}
safeTargets=Collections.synchronizedList(目标);
exec=Executors.newCachedThreadPool();
对于(inti=0;i<4;i++){//线程数
exec.execute(新的Runnable(){
@凌驾
公开募捐{
while(true){
对于(目标t:安全目标){
字符串ping=null;
if(t.isActive()&&!t.isIsBeingPinged()){//检查目标是否已被另一个线程ping,以及它是否标记为活动并希望被ping。
t、 设置为pinged(true);
t、 setPinged(t.getPinged()+1);//看看它被ping了多少次
t、 设置状态(“PINGING”);
试一试{
可调用的c=新的Pinger(t);
ping=c.call().toString();
开关(ping){
案例“超时”:
t、 设置状态(“超时”);
t、 setLastrtt(“超时”);
t、 设置超时(t.timeoutsProperty().get()+1);
logUtil.log(logUtil.INFO,t.nameProperty().get()+“-超时!”);
t、 正在进行设置(错误);
打破
案例“未知主机”:
t、 设置状态(“错误”);
t、 setLastrtt(“未知主机”);
logUtil.log(logUtil.WARNING,t.nameProperty().get()+“-未知主机!”);
t、 正在进行设置(错误);
打破
案例“无法到达”:
t、 设置状态(“错误”);
t、 setLastrtt(“无法访问的主机”);
logUtil.log(logUtil.WARNING,t.nameProperty().get()+“-无法访问!”);
t、 正在进行设置(错误);
打破
违约:
t、 setLastrtt(ping);
t、 设置状态(“活动”);
t、 正在进行设置(错误);
打破
}
System.out.println(“C=“+t.getPinged()+”-“+t.nameProperty().get());
}捕获(例外e){
logUtil.log(logUtil.CRITICAL,e.getMessage()+”,“+e.getCause());
e、 printStackTrace();
}
}
}
}
}
});
}
}
毕竟,我必须摆脱图表中立即添加的内容

  • 目标列表对象被添加到线程安全的synchronizedList中(正如kleopatra所建议的那样)
  • 向目标模型中添加了一个布尔变量,以确定它当前是否正在被其中一个线程ping。(t.isIsBeingPinged())
  • 使用同一池中的新Runnable将数据添加到图表中,该池迭代目标列表并每秒将最后一个RTT添加到图表中,以避免ping较高的目标落后于图表

感谢您的快速响应!

我认为您必须为此创建4个单独的线程,但问题是我需要以某种方式这样做,这样4个单独的线程不会在一个周期内迭代同一个目标t,否则它只会有4个线程同时做相同的事情,这可能会导致ConcurrentModificationEx概念和无意义的冗余。在回答这类命名错误的问题时,JavaFX中有一些在数组上进行多线程调用的示例代码:我确实调用了callable.call(),我只是立即调用了.toString()它位于for循环的顶部,就在切换之前。runnable用于防止JavaFXUI线程变得无响应。Pinger已经实现了Callable。这正是您的问题。通过调用方法call()没有进行多线程处理,您只是有顺序行为。您需要将每个可调用的线程提交给ExecutorService。也许我应该澄清一下;我知道我需要在目标服务器上调用可调用的Pinger