我上了一堂课
@Component
public MyClass {
private volatile boolean stopped = false;
public void verification() throws Exception {
Thread kpiAllThread = getKPIAllThread();
try {
for (int i = 0; i < poolSize; i++) {
execDispatcher.put(processExecutor.submit(getCheckValuesInKPIConsumerTask(workingQueue)));
}
kpiAllThread.start();
} finally {
waitFinished();
}
}
public void setStop(bolean stopped) {
this.stopped = stopped;
}
private Thread getKPIAllThread() {
return new Thread(() -> {
try {
LOG.debug("KPIAllThread started!");
dao.getKpiAll(workingQueue);
for (int i = 0; i < poolSize; i++) {
workingQueue.put(() -> true);
}
} catch (Exception ex) {
LOG.error("KPIAllThread exception: ", ex);
} finally {
LOG.error("KPIAllThread finished!");
}
});
}
}
该类启动生产者线程getKPIAllThread
。他从db获取数据并放入BlockingQueue
。
方法getKpiAll
像这样:
public void getKpiAll(final BlockingQueue<KeyPropertyIndex> kpiData) throws Exception {
LOG.debug("Starting getKpiAll");
try (final Connection con = dataSource.getConnection();
final Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
stmt.setFetchSize(Integer.MIN_VALUE);
try (final ResultSet rs = stmt.executeQuery(sqlGetAllkpi)) {
while (rs.next()) {
kpiData.put(new KeyPropertyIndexData(rs.getLong(1), rs.getString(2)));
}
}
LOG.debug("Finished get getKpiAll");
} catch (Exception ex) {
throw ex;
}
}
还有一个变量stopped
,可以从外部设置为true
。这样做时如何安全地停止线程?这样就关闭了与数据库的所有连接并成功完成了线程?
答案 0 :(得分:2)
停止线程最干净,最安全的规则是,在线程中运行的代码应定期检查条件(例如boolean shouldExit()
)。当代码检测到这种情况为真时,应停止执行操作并终止。
在线程中运行的代码应相当频繁地检查此条件,以便可以合理快速地做出反应。根据经验,设置此条件后,线程应退出不到一秒钟。该检查通常看起来像if (shouldExit()) break
,它在for循环中的某个位置上遍历池大小。但是,dao.getKpiAll(workingQueue)
看起来可能很长,因此您可以在getKpiAll
内放置更多支票。
当您进行此检查时,必须确保每次条件为真时,您的代码将干净退出。例如,您可以使用finally
块来关闭任何连接等。如果在getKpiAll
期间发生这种情况,甚至没有理由继续for
循环来处理项目,依此类推。 / p>
有时,这可能会变得更加棘手-例如,当线程正在等待网络操作时,您可能需要关闭网络套接字或类似的东西才能中断它。无论如何,请避免使用Thread.stop()
或Thread.interrupt()
-请参阅文档,了解它们为何有问题。
如果执行这样的操作,则可以随时从线程外部设置条件以请求终止线程。您可以进行类似void requestExit()
的操作,并在其中设置一个布尔变量。调用requestExit()
之后,您以适当的超时调用Thread.join()
来等待线程处理其事务,检查条件并退出。同样,根据经验,将超时设置为线程的最长响应时间的3到10倍。
看来您已经有setStopped(boolean stopped)
用于此目的,但您没有检查它。首先,我将删除参数stopped
,因为将false
传递给它没有意义。其次,您需要如上所述添加检查。您可能想使此变量对dao
可见-请记住,将其公开为同步布尔方法比将其公开为布尔字段要好得多。