当前位置: 代码迷 >> java >> 我应该如何使用 2 个线程从 DB 收集数据?
  详细解决方案

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

热度:34   发布时间:2023-07-27 09:33:54.0

我有一个包含 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);
    }
}

发生这种情况是因为您正在按顺序启动线程,即当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,因此开发人员指南。

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

您的瓶颈不在于处理 1600 行——这只是太少的记录而无需担心,只有小记录。 您的问题更可能类似于为请求预热新连接所需的时间(在这种情况下,并行使用 2 个冷连接不会为您节省任何时间)。

看看像 C3P0、DBCP 或 HikariCP 这样的连接池服务,只需执行一次获取。

  相关解决方案