让我解释一下我的应用是如何设置的。首先,我有一个独立的命令行启动应用程序,运行一个主程序,然后调用启动作业操作员传递适当的参数。我知道开始是一个异步调用,一旦我调用start,除非我阻止了一些在我的主体中它如何死亡。
我遇到的问题是,当我运行分区作业时,它似乎会留下一些线程,这会阻止整个处理结束。当我运行未分区的作业时,一旦作业完成,该过程就会正常结束。
这是正常和/或预期的行为吗?有没有办法告诉分区线程死亡。看来,一旦作业完成,分区的线程就会被阻塞等待它们不应该是什么?
我知道我可以监控主要的批处理状态并可能结束它但是正如我在另一个问题中所说的那样,这会给数据库带来大量的喋喋不休,并且不太理想。
我的工作规范的一个例子
<job id="partitionTest" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="onlyStep">
<partition>
<plan partitions="2">
<properties partition="0">
<property name="partitionNumber" value="1"></property>
</properties>
<properties partition="1">
<property name="partitionNumber" value="2"></property>
</properties>
</plan>
</partition>
<chunk item-count="2">
<reader id="reader" ref="DelimitedFlatFileReader">
<properties>
<!-- Reads in from file Test.csv -->
<property name="fileNameAndPath" value="#{jobParameters['inputPath']}/CSVInput#{partitionPlan['partitionNumber']}.csv" />
<property name="fieldNames" value="firstName, lastName, city" />
<property name="fullyQualifiedTargetClass" value="com.test.transactionaltest.Member" />
</properties>
</reader>
<processor ref="com.test.partitiontest.Processor" />
<writer ref="FlatFileWriter" >
<properties>
<property name="appendOn" value="true"/>
<property name="fileNameAndPath" value="#{jobParameters['outputPath']}/PartitionOutput.txt" />
<property name="fullyQualifiedTargetClass" value="com.test.transactionaltest.Member" />
</properties>
</writer>
</chunk>
</step>
</job>
编辑:
好的阅读有关此问题的更多信息并查看Spring批处理代码,我认为在JsrPartitionHandler中至少存在一个错误。具体来说,handle方法在本地创建一个ThreadPoolTaskExecutor,但之后该线程池永远不会被正确清理。应该在该方法返回之前调用shutdown / destroy,以便执行一些清理,否则线程将留在内存中并超出范围。
如果我在这里错了,请纠正我,但这肯定是问题所在。
我要去尝试改变它,看看它是如何发挥作用的。我做完一些测试后会更新。
答案 0 :(得分:0)
我已经在spring batch core lib中确认这个问题是一个错误(仍然在我看来atm)。
我在spring batch jira网站上创建了一个ticket。有一个简单的附加java项目到票证,确认我看到的问题。如果其他任何人遇到问题,他们应该参考那张票。
我找到了一个临时工作,只是使用了一个等待/通知方案,似乎一旦添加了池化线程关闭。我将添加每个类/代码并尝试解释我所做的事情。
在主线程/类中,这是生活在main方法中的代码或从main
调用的方法 while(!ThreadNotifier.instance(this).getNotify()){
try {
synchronized(this){
System.out.println("WAIT THREAD IS =======" + Thread.currentThread().getName());
wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这是ThreadNotifier类
public class ThreadNotifier {
private static ThreadNotifier tn = null;
private boolean notification = false;
private Object o;
private ThreadNotifier(Object o){
this.o = o;
}
public static ThreadNotifier instance(Object o){
if(tn == null){
tn = new ThreadNotifier(o);
}
return tn;
}
public void setNotify(boolean value){
notification = true;
synchronized(o){
System.out.println("NOTIFY THREAD IS =======" + Thread.currentThread().getName());
o.notify();
}
}
public boolean getNotify(){
return notification;
}
}
最后,这是一个我曾经提供通知的工作听众
public class PartitionWorkAround implements JobListener {
@Override
public void beforeJob() throws Exception {
// TODO Auto-generated method stub
}
@Override
public void afterJob() throws Exception {
ThreadNotifier.instance(null).setNotify(true);
}
}
在问题得到解决之前,我能想出最好的结果。作为参考,我使用了解有关受保护区块here的知识来找出实现此目的的方法。