我正在尝试实现一个基于某些用户输入编程任务的应用程序。用户可以使用与之关联的telnet命令(一对一关系),执行频率和2组(cluster,objectClass)来放置大量IP。
用户应该能够在运行时添加/删除IP,集群,命令等。他们也应该能够中断执行。
此应用程序应该能够将telnet命令发送到IP,等待响应并根据频率将响应保存在数据库中。我遇到的问题是尝试将所有这些多线程化,因为至少有60,000个IP用于telnet,并且在单个线程中执行它将花费太多时间。一个线程应该使用相同的objectClass处理同一群集中的一组IP。
我看了Quartz来安排工作。使用Quartz,我尝试创建一个动态作业,其中包含IP列表(带有命令),处理它们并将结果保存到数据库。但后来我遇到了用户给出的不同计时器的问题。 Quartz网页上的示例不完整,不会过多详细说明。
然后我尝试使用旧的方式,使用java Threads,但我需要异常处理和参数传递,Threads不这样做。然后我发现了Callables和Executors,但我不能用Callables安排任务。
所以现在我很难过,我该怎么办?
答案 0 :(得分:1)
好的,这是一些想法。带上必要的盐粒。
首先,创建一个需要执行的所有工作的列表。我假设你在表格中有这个,你可以创建一个如下所示的连接:
cluster | objectClass | ip-address | command | frequency | last-run-time
这代表了系统需要完成的所有工作。为了便于解释,我会说频率可以采取“每天1次”,“每小时1次”,“每小时4次”,“每分钟”的形式。该表每行有一行(cluster,objectClass,ip-address,command)。假设一个不同的表具有运行历史记录,包含错误消息和其他内容。
现在您需要做的是阅读该表,并安排工作。如需安排,请使用以下方法之一:
ScheduledExecutorService exec = Executors...
当你安排某些事情时,你需要告诉它经常运行的频率(我们给出的频率很容易)和延迟。如果每分钟运行一次并且最后一次运行4分30秒,则初始延迟为零。如果要每小时运行一次,则初始延迟为(60分钟 - 4.5分钟= 55.5分钟)。
ScheduledFuture<?> handle = exec.scheduleAtFixedRate(...);
更复杂的调度类型是为什么像Quartz这样的东西存在,但基本上你只需要一种方法来解决,给定(调度,最后运行)到下一次执行的经过时间。如果您可以这样做,那么您可以使用schedule(...)代替scheduleAtFixedRate(...),然后在该任务完成时安排下一次运行任务。
无论如何,当你安排某些事情时,你会得到一个回头的手柄
ScheduledFuture<?> handle = exec.scheduleAtFixedRate(...);
将此句柄放在可以访问的内容中。为了论证,让我们说它是TaskKey的地图。 TaskKey是(cluster | objectClass | ip-address |命令)作为对象。
Map<TaskKey,ScheduledFuture<?>> tasks = ...;
您可以使用该句柄取消和安排新作业。
cancelForCustomer(CustomerId id) {
List<TaskKey> keys = db.findAllTasksOwnedByCustomer(id);
for(TaskKey key : keys) {
ScheduledFuture<?> f = tasks.get(key);
if(f!=null) f.cancel();
}
}
对于参数传递,创建一个对象来表示您的工作。使用您需要的所有参数创建其中一个。
class HostCheck implements Runnable {
private final Address host;
private final String command;
private final int something;
public HostCheck(Address host, String command; int something) {
this.host = host; this.command = command; this.something = something;
}
....
}
对于异常处理,将所有内容本地化为对象
class HostCheck implements Runnable {
...
public void run() {
try {
check();
scheduleNextRun(); // optionally, if fixed-rate doesn't work
} catch( Exception e ) {
db.markFailure(task); // or however.
// Point is tell somebody about the failure.
// You can use this to decide to stop scheduling checks for the host
// or whatever, but just record the info now and us it to influence
// future behavior in, er, the future.
}
}
}
好的,到目前为止,我认为我们的状态非常好。需要填写很多细节,但感觉很容易管理。现在我们遇到了一些复杂性,这就要求“cluster / objectClass”对的执行是串行的。
有几种方法可以解决这个问题。
如果唯一对的数量很少,您只需创建Map<ClusterObjectClassPair,ScheduledExecutorService>
,确保创建单线程执行程序服务(例如Executors.newSingleThreadScheduledExecutor()
)。因此,您不必使用单个调度服务(上面为exec
)。很简单。
如果您需要控制同时尝试的工作量,那么您可以让每个HealthCheck在执行前获得许可。有一些全球许可对象
public static final Semaphore permits = java.util.concurrent.Semaphore(30);
然后
class HostCheck implements Runnable {
...
public void run() {
permits.acquire()
try {
check();
scheduleNextRun();
} catch( Exception e ) {
// regular handling
} finally {
permits.release();
}
}
}
每个ClusterObjectClassPair
只有一个帖子,用于序列化该工作,然后允许一次限制您可以与之交谈的ClusterObjectClassPair
个。{/ p>
我想这让它变成了一个很长的答案。祝你好运。