Java并发查询

发布于 2024-10-20 18:42:44 字数 1418 浏览 5 评论 0 原文

我正在用 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 有两个核心,所以应该可以一次运行两个多线程,对吗?

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

感谢您的时间和帮助!

更新 - 添加了 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;
}

I´m building a benchmarkapplication in Java as experiment. The purpose of the tool is to find out how fast a specific database (like Derby, MySQL for example) is in different settings.

At the moment I'm trying to find out how fast a database is when executing multiple queries at the same time.

I thought of creating multiple threads where each thread executes multiple queries. But at the moment the queries seems to be executed after the other query is finished instead of concurrently.

I've got the following (simplified) code:

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

       }
    }
}

The cpu of mine testsystem has two cores so it should be possible to run two multiple threads at a time, right?

Somebody an idea how to implement this option?

Thank you for your time and help!

UPDATE - added selectData method code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里°也失望 2024-10-27 18:42:44

这里有两个问题:

  1. 您必须等到所有线程都完成。这可以手动完成,但不使用线程要容易得多,而是使用 ExecutorService 为您提供了诸如 invokeAll()awaitTermination() 之类的方法来为您执行此操作。要获取 ExecutorService,请使用 Executors 类中的方法。此类还提供将 Runnable 包装为 Callable 的方法。因此,在 main 方法中,您将创建一个 ExecutorService,在 for 循环中提交所有可运行对象,调用 shutdown()awaitTermination()。然后,打印计数器的值。
  2. 您必须注意正确添加时间。为此,每个 Runnable 实例使用自己的秒表非常重要,因此 stopwatch2 变量需要是 run() 的局部变量。另外,counter 变量不能是普通的 long,但它需要是 AtomicLong。否则,某些线程的时间可能会丢失,因为正常的加法不是原子操作(两个线程可能会尝试同时将其时间添加到计数器变量,这可能会导致错误的结果)。

这是代码:

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

       }
    }
}

There are two problems here:

  1. You have to wait until all Threads have finished. This can be done manually, but it is much easier to not use Threads, but an ExecutorService which offers you methods like invokeAll() or awaitTermination() that do this for you. To get an ExecutorService, use the methods from the Executors class. This class also offers methods to wrap Runnable into Callable. So in the main method you would create an ExecutorService, submit all the runnables in the for loop, call shutdown() and awaitTermination(). Then, print the value of the counter.
  2. You have to take care of adding the times correctly. For this it is important that each Runnable instance uses its own stopwatch, so the stopwatch2 variable needs to be a local variable of run(). Also, the counter variable cannot be a normal long, but it needs to be an AtomicLong. Otherwise the times of some threads could get lost, because normal addition is not an atomic operation (two threads could try to add their times to the counter variable at the same time, which would probably cause a wrong result).

Here's the code:

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

       }
    }
}
吾家有女初长成 2024-10-27 18:42:44

如果您在线程之间共享相同的 SQL 连接,那么这可能是您的问题。一般来说,您应该避免在不同线程之间共享相同的连接,而应使用连接池。

If you share the same SQL Connection between the threads then that might be your problem. In general you should avoid sharing the same connection between different threads and use connection pools instead.

停滞 2024-10-27 18:42:44

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

要解决这个问题,您要么需要删除同步(显然不会破坏任何东西),要么每个线程有一个单独的 dataHandler (前提是相关类支持这一点。)

The most likely cause of the behaviour you describe is that dataHandler.selectData() either is synchronized or relies on a synchronized method do the work.

To solve this, you either need to remove the synchronization (obviously without breaking things), or have a separate dataHandler per thread (provided the class in question supports that.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文