我正在一个多线程项目中工作,其中每个线程将randomly find columns for that table
,我将在我的SELECT sql query
中使用这些列,然后我将执行SELECT sql查询。在执行该查询之后,我将遍历结果集,并将每个列的数据添加到List<String>
中。
这里columnsList
将包含由comma
分隔的columns
。例如,
col1, col2, col3
下面是我的代码。
class ReadTask implements Runnable {
public ReadTask() {
}
@Override
public run() {
...
while ( < 60 minutes) {
.....
final int id = generateRandomId(random);
final String columnsList = getColumns(table.getColumns());
final String selectSql = "SELECT " + columnsList + " from " + table.getTableName() + " where id = ?";
resultSet = preparedStatement.executeQuery();
List<String> colData = new ArrayList<String>(columnsList.split(",").length);
boolean foundData = false;
if (id >= startValidRange && id <= endValidRange) {
if (resultSet.next()) {
foundData = true;
for (String column : columnsList.split(",")) {
colData.add(resultSet.getString(column.trim()));
}
resultSet.next();//do I need this here?
}
} else if (resultSet.next()) {
addException("Data Present for Non Valid ID's", Read.flagTerminate);
}
....
}
}
private static void addException(String cause, boolean flagTerminate) {
AtomicInteger count = exceptionMap.get(cause);
if (count == null) {
count = new AtomicInteger();
AtomicInteger curCount = exceptionMap.putIfAbsent(cause, count);
if (curCount != null) {
count = curCount;
}
}
count.incrementAndGet();
if(flagTerminate) {
System.exit(1);
}
}
}
问题陈述:-
执行SELECT
sql查询后。下面是我的两个场景——
- 我需要看看id是否在有效范围内。如果在Valid Range之间,则检查
resultSet
是否有任何数据。如果它有数据,那么使用columnsList
中的columns
循环resultSet
,并开始将其添加到字符串的coldData
列表中。 - 否则,如果id不在有效范围内,那么我需要检查我没有从
resultSet
获得任何数据。但不知何故,如果我得到的数据,并标志为真,停止程序,然后退出程序。否则,如果我正在获取数据,但标志为false以停止程序,则计算发生了多少次。因此,我创建了addException
方法。
有没有人可以帮助我,我在这里为我上面两个scenarios
做的方式是正确的还是不?看起来,我可以改进if/else loop
代码更多,我想我的上述两个场景。
您可以做一些事情来让代码更快一点:
关于查询部分,如果表从未更改,您可以将columnsList
初始化移到while循环之外,如果所有线程使用相同的查询,甚至可以将其设置为静态。同样,您将为每个查询结果重新计算该变量的拆分和修剪列列表。这可以在循环外一次性完成。
关于测试本身,确实可以反转嵌套。您当前正在执行的操作如下:
if (B) {
if (A) ok;
}
else if (A) error;
可以更简单地写成:
if (A){
if (B) ok;
else error;
}
您的代码可以更好地表述如下:
if (resultSet.next()) {
if (id >= startValidRange && id <= endValidRange) {
foundData = true;
for (String column : columnsList.split(",")) {
colData.add(resultSet.getString(column.trim()));
}
}
else
addException("Data Present for Non Valid ID's", Read.flagTerminate);
}
关于异常日志部分,您应该避免使用静态方法直接在映射中处理存储,这是一个非常强大的争用来源,并且会阻止线程专注于执行它们的实际工作,即启动和处理查询。通常,在O(log n)
中访问map具有时间复杂度,并且查看您的代码,您将进行两次访问,并进行各种检查以确保会计正确。相比之下,在队列中推送值是一个常量时间操作,同步由队列本身处理。
所以,我的建议是把map的处理委托给一个专用的线程,并为你的查询线程添加一个同步队列来给它异常。这样就不需要处理对映射的并发访问(这可能会很混乱)。同样,从查询线程的角度来看,日志记录过程将是一个简单的"即发即忘"操作,日志记录线程只需要从队列中提取新消息并将它们添加到映射中。
如果您还不知道如何构建这样的设置,可以参考Oracle教程。关于这个主题(生产者-消费者)也有几个问题和答案。
更新:如果你甚至想减少争用,你可以为每个查询线程创建一个队列,并让map线程依次检查所有队列。并发访问的风险减少到同时有两个线程:一个查询线程和一个映射线程。它将在map线程中引入更多的工作,但同时将避免许多线程重新调度(每次线程被锁阻塞时都会发生这种情况)。重新调度发生得越少,花在线程管理上的时间就越少,有更多的时间可用于实际工作。
注意,无论如何,您都应该注意不要有太多的项堆积在队列中。如果这种情况很可能发生(我怀疑,但我不知道您的数据的细节是肯定的),您可能希望使用BlockingQueues(查找类描述,并进一步详细了解主题的SO问题)。