简体   繁体   English

Java并发查询

[英]Java concurrent queries

I´m building a benchmarkapplication in Java as experiment. 我正在用Java构建一个基准应用程序作为实验。 The purpose of the tool is to find out how fast a specific database (like Derby, MySQL for example) is in different settings. 该工具的目的是找出特定数据库(例如Derby,MySQL)在不同设置下的运行速度。

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? 我的testsystem的cpu有两个内核,因此应该可以一次运行两个多线程,对吗?

Somebody an idea how to implement this option? 有人知道如何实现此选项吗?

Thank you for your time and help! 感谢您的时间和帮助!

UPDATE - added selectData method code : 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;
}

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. 这可以手动完成,但是不使用线程要容易得多,但是可以使用ExecutorService为您提供诸如invokeAll()awaitTermination()类的方法。 To get an ExecutorService , use the methods from the Executors class. 要获取ExecutorService ,请使用Executors类中的方法。 This class also offers methods to wrap Runnable into Callable . 此类还提供了将Runnable包装为Callable So in the main method you would create an ExecutorService , submit all the runnables in the for loop, call shutdown() and awaitTermination() . 因此,在main方法中,您将创建一个ExecutorService ,在for循环中提交所有可运行对象,调用shutdown()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() . 为此,每个Runnable实例都使用自己的秒表很重要,因此stopwatch2变量必须是run()的局部变量。 Also, the counter variable cannot be a normal long, but it needs to be an AtomicLong . 同样, counter变量不能为正常的long,但必须为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());

       }
    }
}

If you share the same SQL Connection between the threads then that might be your problem. 如果您在线程之间共享相同的SQL连接,则可能是您的问题。 In general you should avoid sharing the same connection between different threads and use connection pools instead. 通常,应避免在不同线程之间共享相同的连接,而应使用连接池。

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. 您描述的行为的最可能原因是dataHandler.selectData()synchronized还是依靠synchronized方法来完成工作。

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.) 要解决此问题,您要么需要删除同步(显然不会破坏事情),要么每个线程有一个单独的dataHandler (前提是所讨论的类支持该处理)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM