我应该如何使用2个线程从DB收集数据?

时间:2019-02-13 03:00:35

标签: java database

我有一个带有1600多个记录的数据库,读取所有记录看起来很慢,所以我有了一个使用2个线程来获取数据的想法。我具有以下功能,但感觉不快...

private ArrayList<Worker> getWorkersOnMultipleThread() throws InterruptedException {
    ArrayList<Worker> totalWorkers = new ArrayList<>();
    ArrayList<Worker> totalWorkers2 = new ArrayList<>();
    int total = db.getNumberOfWorkers();
    int firstHalf, secondHalf;
    firstHalf = total / 2;
    if (total % 2 == 1) {
        secondHalf = total / 2 + 1;
    } else {
        secondHalf = total / 2;
    }

    Thread t1 = new Thread() {
        @Override
        public void run() {
            ArrayList<Worker> w1 = db.getHalfOfTheWorkers(firstHalf, true);
            totalWorkers.addAll(w1);
        }
    };

    Thread t2 = new Thread() {
        @Override
        public void run() {
            ArrayList<Worker> w2 = db.getHalfOfTheWorkers(secondHalf, false);
            totalWorkers2.addAll(w2);
        }
    };

    t1.start();
    t1.join();
    t2.start();
    t2.join();

    totalWorkers.addAll(totalWorkers2);

    return totalWorkers;
}

@Override
public ArrayList<Worker> getHalfOfTheWorkers(int limit, Boolean firstHalf) {
    String sql;
    ArrayList<Worker> workers = new ArrayList<>();
    if (firstHalf) {
        sql = "SELECT * FROM NAMES ORDER BY ID FETCH NEXT " + limit + " ROWS ONLY";
    } else {
        sql = "SELECT * FROM NAMES ORDER BY ID OFFSET " + limit + " ROWS";
    }
    try {
        ResultSet rs = statement.executeQuery(sql);
        while (rs.next()) {
            String name = rs.getString("name");
            int id = rs.getInt("id");
            workers.add(new Worker(id, name));
        }
    } catch (Exception ex) {

    }
    return workers;
}

我的想法是在第一个线程上获取前50%的记录,然后在第二个线程上获取后50%的记录,希望有一半的时间需要获取所有记录。它似乎不起作用(我的意思是它没有错误和内容,并且具有相同的速度...)

主要:

@Override
public void initialize(URL url, ResourceBundle rb) {
    ArrayList<Worker> totalWorkers = new ArrayList<>();
    try {
        totalWorkers = getWorkersOnMultipleThread();
        System.out.println(totalWorkers.size());
    } catch (InterruptedException ex) {
        Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
    }
}

2 个答案:

答案 0 :(得分:1)

之所以发生这种情况,是因为您是按顺序启动线程的,也就是说,t1启动时,main处于使用t1.join()的等待状态。在t2线程完成执行之前,不会启动t1线程。

t1.start();
t1.join(); //main waiting
t2.start();
t2.join();

因此您需要更改顺序:

t1.start();
t2.start();
t1.join(); //main waiting
t2.join();

这样,线程t1t2将同时启动,并且您将指示main等待t1t2都完成执行。

理想情况下,statement对象不应在线程之间共享。您应该从线程池中为每个线程获取一个Connection对象。

由于您使用的是Apache derby,因此请参见开发人员指南discourages the sharing of connection

  
      
  • 避免在线程之间共享语句(及其结果集)。每次线程执行一个Statement时,它应该在放弃Connection之前先处理结果。
  •   
  • 每次线程访问Connection时,它都应根据应用程序协议一致地提交或不提交。
  •   
  • 只有一个线程是“管理”数据库连接线程,该线程应该处理更高级别的任务,例如建立
      连接,提交,回滚,更改连接属性
      例如自动提交,关闭连接,关闭
      数据库(在嵌入式环境中),等等。
  •   
  • 关闭为了释放资源不再需要的ResultSet和语句。
  •   

答案 1 :(得分:0)

您的瓶颈不在处理1600行中-这简直是令人担忧的记录太少了,那是很小的记录。您的问题很可能类似于为请求预热新连接所需的时间(在这种情况下,并行使用2个冷连接将不会节省您的任何时间)。

查看诸如C3P0,DBCP或HikariCP之类的连接池服务,只需执行一次提取。

相关问题