我正在尝试将Quartz顺序执行更改为并行执行。
它工作正常,性能方面也不错,但是生成(创建)的线程没有被破坏。
它仍然处于Runnable
状态;为什么以及如何解决该问题?
请引导我。
代码在这里:
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
threadPoolExecuter.setQueueCapacity(100);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexams=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexams.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone);
threadPoolExecuter.submit(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
Log.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}
UpdateUserExamDataThread .class
@Component
//@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
//public class UpdateUserExamDataThread extends ThreadLocal<String> //implements Runnable {
public class UpdateUserExamDataThread implements Runnable {
private Logger log = Logger.getLogger(UpdateUserExamDataThread.class);
@Autowired
ExamService examService;
@Autowired
TestEvaluator testEvaluator;
private Object[] obj;
private String timeZone;
public UpdateUserExamDataThread(Object[] obj,String timeZone) {
super();
this.obj = obj;
this.timeZone = timeZone;
}
@Override
public void run() {
String threadName=String.valueOf(obj[0]);
log.info("UpdateUserExamDataThread Start For:::::"+threadName);
testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
//update examResult
log.info("UpdateUserExamDataThread End For:::::"+threadName);
}
}
TestEvaluatorImpl.java
@Override
@Transactional
public Examresult generateTestResultAsPerEvaluator(Long userExamId, String evaluatorType, String codingLanguage,String timeZoneFollowed ,String inctenceId ,String userId) {
dbSchema = messageService.getMessage("database.default_schema", null, Locale.getDefault());
try {
//Some Methods
return examResult;
}catch(Exception e){
log.erorr(e);
}
}
如果需要,我可以提供线程转储文件。
答案 0 :(得分:3)
我怀疑您的线程之一无限期地等待IO请求的答案。例如,您尝试连接到未设置连接超时且主机不应答的远程主机。在这种情况下,可以通过运行基础shutdownNow
的{{1}}方法来强制关闭所有正在执行的任务,然后可以分析有问题的线程抛出的InterruptedIOException。
替换
ExecutorService
带有以下内容,您可以检查错误。
threadPoolExecuter.shutdown();
这会将interrupt信号发送到所有正在运行的线程。
答案 1 :(得分:3)
似乎您在相同大小的考试中创建了一个线程池,这并不是很理想。
// Core pool size is = number of exams
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
// Max pool size is just 1 + exam size.
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
您必须考虑: -如果您创建了一个线程池并启动了该线程池,则将立即启动与核心大小中定义的线程一样多的线程。
在您的情况下,我将核心池大小设置为5或10(实际上取决于目标CPU拥有多少个核心和/或IO绑定提交的任务的方式)。
最大池大小可以是最大池大小的两倍,但是直到队列满时才有效。
要使活动线程的大小在提交的工作完成后减小,您必须设置2个参数。
setKeepAliveSeconds(int keepAliveSeconds):如果未在定义的秒数内使用它们(默认情况下为60秒,这是最佳选择),则线程将自动关闭,但通常这只是用于关闭非核心池线程的线程。
要在keepAliveSeconds之后关闭核心部分的线程,必须将 setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut)设置为true。只要应用程序正在运行,通常就不能使核心池保持活动状态。
我希望它会有所帮助。
答案 2 :(得分:0)
线程不等待来自某些远程服务器的IO,因为线程上执行的方法将在某些jdbc驱动程序类中,但是它们当前都在UpdateUserExamDataThread.run()的第37行中。
现在的问题是:UpdateUserExamDataThread.java第37行的代码是什么? 不幸的是,目前给出的UpdateUserExamDataThread.java不完整和/或未真正执行该版本:缺少包声明,它在第29行结束。
答案 3 :(得分:0)
我怀疑问题很简单,您是在使用Submit()生成任务线程时调用run()而不是execute()的。在使用Submit时,可能会有一些期望,即线程会在任务完成时杀死自己,而不是在run方法的结尾处终止。
答案 4 :(得分:0)
只需增加线程的优先级并根据处理器中的内核数创建线程数。
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
int cores = Runtime.getRuntime().availableProcessors();
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(cores);
// threadPoolExecuter.setMaxPoolSize(Integer.MAX_VALUE);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
// threadPoolExecuter.setQueueCapacity(Integer.MAX_VALUE);
threadPoolExecuter.setQueueCapacity(lstOfExams.size()+10);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.setWaitForTasksToCompleteOnShutdown(true);
threadPoolExecuter.setThreadPriority(10);
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexam=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexam.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone,testEvaluator);
// threadPoolExecuter.submit(task);
threadPoolExecuter.execute(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
logger.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}