问题描述
我有一个包含 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);
}
}
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();
这样,线程t1
和t2
将并行启动,您将指示 main 等待,直到t1
和t2
都完成执行。
理想情况下, statement
对象不应在线程之间共享。
您应该从线程池中为每个线程获取一个Connection
对象。
由于您使用的是 Apache derby,因此开发人员指南。
- 避免在线程之间共享语句(及其结果集)。 线程每次执行 Statement 时,都应该在放弃 Connection 之前处理结果。
- 每次线程访问 Connection 时,它都应该始终提交或不提交,具体取决于应用程序协议。
- 有一个线程是“管理”数据库连接线程,它应该处理更高级别的任务,例如建立
连接、提交、回滚、更改连接属性
例如自动提交、关闭连接、关闭
数据库(在嵌入式环境中),等等。- 关闭不再需要的结果集和语句以释放资源。
2楼
您的瓶颈不在于处理 1600 行——这只是太少的记录而无需担心,只有小记录。 您的问题更可能类似于为请求预热新连接所需的时间(在这种情况下,并行使用 2 个冷连接不会为您节省任何时间)。
看看像 C3P0、DBCP 或 HikariCP 这样的连接池服务,只需执行一次获取。