Java并发查询

时间:2011-03-09 11:00:40

标签: java multithreading concurrency benchmarking

我在Java中构建了一个基准测试应用程序作为实验。该工具的目的是找出特定数据库(例如Derby,MySQL)在不同设置中的速度。

目前我正试图找出同时执行多个查询时数据库的速度。

我想过创建多个线程,每个线程执行多个查询。但目前查询似乎是在另一个查询完成后执行而不是同时执行。

我有以下(简化)代码:

Runner testCase = new Runner();

for (int i = 0; i < THREAD_COUNT; i++) {
    Thread testThread = new Thread(testCase);
    testThread.start();
}

public class Runner implements Runnable {

    public void run() {

      for (int i = 0; i < Benchmarker.QUERY_COUNT; i++) {

        stopwatch2.start();
        List<Person> selectData = dataHandler.selectData();
        stopwatch2.stop();
        counter += stopwatch2.getStopwatchValue();

       }
    }
}

我的测试系统的cpu有两个核心,所以一次可以运行两个多线程,对吗?

有人知道如何实施这个选项吗?

感谢您的时间和帮助!

UPDATE - 添加了selectData方法代码

public List<Person> selectData() {

List<Person> data = new ArrayList<Person>();

try {
    // Select all persons from the database
    ResultSet resultSet = connection.prepareStatement("SELECT * FROM PERSON ORDER BY name").executeQuery();

    // Add all the persons to a arraylist
    while (resultSet.next()) {
    data.add(new Person(resultSet.getString("name")));
    }

    // Close the resultset
    resultSet.close();

} catch (SQLException ex) {
    Logger.getLogger(Derby.class.getName()).log(Level.SEVERE, null, ex);
}

return data;
}

3 个答案:

答案 0 :(得分:4)

这里有两个问题:

  1. 你必须等到所有线程都完成。这可以手动完成,但不使用线程更容易,但ExecutorService为您提供了invokeAll()awaitTermination()等方法。要获得ExecutorService,请使用Executors类中的方法。该类还提供了将Runnable包装到Callable中的方法。因此,在main方法中,您将创建ExecutorService,在for循环中提交所有runnable,调用shutdown()awaitTermination()。然后,打印计数器的值。
  2. 您必须正确地添加时间。为此,每个Runnable实例使用自己的秒表非常重要,因此stopwatch2变量必须是run()的局部变量。此外,counter变量不能是正常的长度,但它必须是AtomicLong。否则,某些线程的时间可能会丢失,因为正常添加不是原子操作(两个线程可能会尝试同时将它们的时间添加到计数器变量,这可能会导致错误的结果)。
  3. 以下是代码:

    void runTests() {
      Runner testCase = new Runner();
      ExecutorService executor = Executors.newCachedThreadPool();
    
      for (int i = 0; i < THREAD_COUNT; i++) {
        executor.execute(testCase);
      }
      executor.shutdown();
      executor.awaitTermination(60, TimeUnit.SECONDS);
      System.out.println(counter.toString());
    }
    
    private AtomicLong counter = new AtomicLong();
    
    public class Runner implements Runnable {
    
        public void run() {
          StopWatch stopwatch2 = ... // get a stopwatch instance here
    
          for (int i = 0; i < Benchmarker.QUERY_COUNT; i++) {
    
            stopwatch2.start(); // this needs to reset the stopwatch to 0
            List<Person> selectData = dataHandler.selectData();
            stopwatch2.stop();
            counter.addAndGet(stopwatch2.getStopwatchValue());
    
           }
        }
    }
    

答案 1 :(得分:3)

如果您在线程之间共享相同的SQL连接,则可能是您的问题。通常,您应该避免在不同线程之间共享相同的连接,而是使用连接池。

答案 2 :(得分:0)

您描述的行为的最可能原因是dataHandler.selectData()要么synchronized要么依赖synchronized方法才能正常工作。

要解决此问题,您需要删除同步(显然不会破坏事物),或者每个线程都有一个单独的dataHandler(假设有问题的类支持它。)