电贺!
我正在用Java编写一个简单的服务器监控应用程序(JavaFX8)。当前的实现能够逐个ping目标机器,并将它们绘制到JavaFX LineChart上。每台机器都是一个“Target”对象,它保存在ArrayList(Observable)中。我的问题是“一个接一个”的部分。 ping目标的代码是一个返回ping的Callable。我不知何故需要多线程处理这个过程,这样我就可以一次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);
}
答案 0 :(得分:1)
我的印象是你将Callable类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()
你的Pinger应该是这样的:
public class Pinger implements Callable<String>{
Pinger(Target target){ ... }
public String call(){ ... }
}
在这里,您可以找到完全实施的Example for Callables。在您的代码中,您只向ExecutorService提交一个Runnable,因此只有两个线程(Main和Runnable)。你永远不会调用方法call(),这是由ExecutorService完成的。将此与Runnable接口相比较,您必须执行Thread调用start或将其提交给ExecutorService而不是调用run();您使用submit()期间返回的Future。试着理解Callable的概念,然后你就可以写出你想要的一切。 ; - )
答案 1 :(得分:0)
所以,继承了当前的工作实施......
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();
}
}
}
}
}
});
}
}
毕竟我不得不摆脱对图表的直接添加。
感谢您的快速回复!