我的两个类中有一个名为process
的方法,比方说CLASS-A and CLASS-B
。现在在下面的循环中,我正在调用我的两个类的process method
顺序意义,它一个接一个地工作正常,但这不是我想要的方式。
for (ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
final Map<String, String> response = entry.getPlugin().process(outputs);
// write to database
System.out.println(response);
}
有什么办法,我可以用多线程的方式调用我的两个类的进程方法。这意味着一个线程将调用CLASS-A的处理方法,第二个线程将调用CLASS-B的处理方法。
之后我想将process
方法返回的数据写入数据库。所以我可以再写一个线程来写入数据库。
以下是我以多线程方式提出的代码,但不知道它根本没有运行。
public void writeEvents(final Map<String, Object> data) {
// Three threads: one thread for the database writer, two threads for the plugin processors
final ExecutorService executor = Executors.newFixedThreadPool(3);
final BlockingQueue<Map<String, String>> queue = new LinkedBlockingQueue<Map<String, String>>();
@SuppressWarnings("unchecked")
final Map<String, String> outputs = (Map<String, String>)data.get(ModelConstants.EVENT_HOLDER);
for (final ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
executor.submit(new Runnable () {
public void run() {
final Map<String, String> response = entry.getPlugin().process(outputs);
// put the response map in the queue for the database to read
queue.offer(response);
}
});
}
Future<?> future = executor.submit(new Runnable () {
public void run() {
Map<String, String> map;
try {
while(true) {
// blocks until a map is available in the queue, or until interrupted
map = queue.take();
// write map to database
System.out.println(map);
}
} catch (InterruptedException ex) {
// IF we're catching InterruptedException then this means that future.cancel(true)
// was called, which means that the plugin processors are finished;
// process the rest of the queue and then exit
while((map = queue.poll()) != null) {
// write map to database
System.out.println(map);
}
}
}
});
// this interrupts the database thread, which sends it into its catch block
// where it processes the rest of the queue and exits
future.cancel(true); // interrupt database thread
// wait for the threads to finish
try {
executor.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
//log error here
}
}
但是,如果我删除最后一行executor.awaitTermination(5, TimeUnit.MINUTES);
,那么它开始运行正常,经过一段时间后,我总是得到这样的错误 -
JVMDUMP006I Processing dump event "systhrow", detail "java/lang/OutOfMemoryError" - please wait.
JVMDUMP032I JVM requested Heap dump using 'S:\GitViews\Stream\goldseye\heapdump.20130827.142415.16456.0001.phd' in response to an event
JVMDUMP010I Heap dump written to S:\GitViews\Stream\goldseye\heapdump.20130827.142415.16456.0001.phd
JVMDUMP006I Processing dump event "systhrow", detail "java/lang/OutOfMemoryError" - please wait.
任何人都可以帮我弄清问题是什么,我在上面的代码中做了什么错误?如果我按顺序运行,那么我没有得到任何错误,它工作正常。
与我的工作方式相比,还有更好的方法吗?因为将来我可以有两个插件处理器。
我想要做的是 - 以多线程的方式调用我的两个类的进程方法,然后写入数据库bcoz我的进程方法将返回一个Map。
任何帮助都将在此得到赞赏..如果可能的话,我正在寻找一个可行的例子。谢谢你的帮助,
答案 0 :(得分:1)
您粘贴的代码段几乎没有问题,如果您修复它们,这应该有用 1.您正在使用无限循环从阻塞队列中获取元素,并尝试使用future来解决此问题。这绝对不是一个好方法。这种方法的问题是,您的数据库线程可能永远不会运行,因为即使在运行之前,调用程序线程中运行的未来任务也可能会取消它。这很容易出错 - 你应该运行while循环固定次数(你已经知道有多少生产者或者你要获得响应的次数)。
此外,提交给执行程序服务的任务应该是独立的任务...这里您的数据库任务依赖于其他任务的执行。如果您的执行策略发生更改,这也可能导致死锁...例如,您使用单线程池执行程序,如果计划数据库线程,它将阻止等待生成器在队列中添加数据。
public void writeEvents(final map data){
final ExecutorService executor = Executors.newFixedThreadPool(3);
@SuppressWarnings("unchecked")
final Map<String, String> outputs = (Map<String, String>)data.get(ModelConstants.EVENT_HOLDER);
for (final ModuleRegistration.ModulesHolderEntry entry : ModuleRegistration.getInstance()) {
executor.submit(new Runnable () {
public void run() {
try {
final Map<String, String> response = entry.getPlugin().process(outputs);
//process the response and update database.
System.out.println(map);
} catch (Throwable e) {
//handle execption
} finally {
//clean up resources
}
}
});
}
//这将等待运行线程完成..这是一个有序的关闭。 executor.shutdown(); }
答案 1 :(得分:0)
好的,这是我上面建议的评论的一些代码。免责声明:我不确定它是否有效甚至可以编译,或者它是否能解决问题。但我们的想法是控制取消过程,而不是依赖于我怀疑可能导致问题的future.cancel
。
class CheckQueue implements Runnable {
private volatile boolean cancelled = false;
public void cancel() { cancelled = true; }
public void run() {
Map<String, String> map;
try {
while(!cancelled) {
// blocks until a map is available in the queue, or until interrupted
map = queue.take();
if (cancelled) break;
// write map to database
System.out.println(map);
} catch (InterruptedException e) {
}
while((map = queue.poll()) != null) {
// write map to database
System.out.println(map);
}
}
}
CheckQueue queueChecker = new CheckQueue ();
Future<?> future = executor.submit(queueChecker);
// this interrupts the database thread, which sends it into its catch block
// where it processes the rest of the queue and exits
queueChecker.cancel();