2

我正在开发一个多线程项目,其中每个线程都randomly find columns for that table将使用这些列SELECT sql query,然后我将执行该 SELECT sql 查询。执行该查询后,我将遍历结果集并将每列的数据添加到List<String>.

这里columnsList将包含columnscomma. 例如-

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);
        }
    }
}

问题陈述:-

执行SELECTsql查询后。以下是我的两种情况-

  1. 我需要查看 id 是否在有效范围之间。如果它在有效范围之间,则检查是否resultSet有任何数据。resultSet如果它有数据,则使用columnsfrom循环columnsList并开始将其添加coldData到字符串列表中。
  2. 否则,如果 id 不在有效范围内,那么我需要检查我没有从resultSet. 但不知何故,如果我取回数据并且标志为真以停止程序,然后退出程序。否则,如果我要取回数据但标志为假以停止程序,则计算其中发生了多少。所以为此,我创建了addException方法。

谁能帮我看看我在这里为上述两个做的方式是否scenarios正确?看起来,if/else loop对于上述两种情况,我可以进一步改进代码。

4

1 回答 1

2

您可能可以做一些事情来使代码更快一点:

关于查询部分,如果表从未更改,则可以将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),并且查看您的代码,您将进行两次访问,并进行各种检查以确保记帐正确。相比之下,将值推送到队列中是一个常数时间的操作,同步由队列本身处理。

因此,我在这里的建议是将映射的处理委托给一个专用线程,并为您的查询线程添加一个同步队列以使其异常。这样您就不需要处理对地图的并发访问(这可能很混乱)。同样,从查询线程的角度来看,日志记录过程将是一个简单的“触发并忘记”操作,并且日志记录线程只需从队列中提取新消息并将它们添加到映射中。

如果您还不知道如何构建这样的设置,请参阅 Oracle 教程。关于该主题(生产者-消费者)还有几个 SO 问题和答案。

更新:如果您想减少争用,您可以为每个查询线程创建一个队列,并让映射线程依次检查所有队列。并发访问的风险降低到同时两个线程:一个查询线程和一个映射线程。它会在映射线程中引入更多工作,但同时会避免许多线程重新调度(每次线程被锁阻塞时都会发生这种情况)。重新调度的次数越少,花在线程管理上的时间就越少,用于实际工作的时间就越多。

请注意,无论如何,您应该注意不要在队列中堆积太多项目。如果这种情况很可能发生(我对此表示怀疑,但我不确定您的数据的详细信息),您可能想要使用 BlockingQueues (查找类描述和有关该主题的 SO 问题以获取更多详细信息)。

于 2013-03-01T03:17:03.437 回答