synchronized 是否锁定结果集对象?
Does synchronized lock a Result Set object?
我正在尝试对结果集进行多线程处理。我想确保每当我在多个线程之一中调用 next()
时,所有其他线程都被锁定。这很重要,因为如果许多线程同时调用 next()
方法,这将导致跳过这些行。这是我做的
public class MainClass {
private static ResultSet rs;
public static void main (String [] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
runWhile();
}});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
runWhile();
}});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.exit(0);
}
private static void runWhile () {
String username = null;
while ((username = getUsername()) != null) {
// Use username to complete my logic
}
}
/**
* This method locks ResultSet rs until the String username is retrieved.
* This prevents skipping the rows
* @return
* @throws SQLException
*/
private synchronized static String getUsername() throws SQLException {
if(rs.next()) {
return rs.getString(1).trim();
}
else
return null;
}
}
这是使用 synchronized
的正确方法吗?它是否锁定 ResutSet
并确保其他线程不干扰?
这是一个好方法吗?
JDBC 对象不应在线程之间共享。这适用于连接、语句和结果集。这里最好的情况是 JDBC 供应商遵循规范并进行内部锁定,这样您就可以解决这个问题,在这种情况下,所有线程仍在尝试获取相同的锁,只有一个可以取得进展一次。这将比使用单个线程慢,因为除了从数据库中读取相同的工作之外,管理所有线程还会产生额外的开销。
(驱动程序完成的锁定可能是为了驱动程序的利益,因此提供商不必处理因用户滥用其软件而导致的竞争条件错误报告。它确实锁定并不一定意味着软件实际上应该被多个线程使用。)
多线程在线程可以同时取得进展时有效,请参阅 Amdahl's Law。如果您遇到可以读取 ResultSet 并使用结果创建提交给 ExecutorService 的任务(正如 Peter Lawrey 在评论中建议的那样),那么这将更有意义(只要这些任务可以独立工作并且不必须互相等待)。
我建议创建结果集,然后将所有数据复制到 DTO(数据传输对象)或 DAO(数据访问对象)中。在 DTO 或 DAO 上获得数据后,关闭您的 ResultSet、Statement 和 Connection。
创建 DTO/DAO 以按顺序存储记录、其字段和解析功能的非常简单的结构是这样的:
ArrayList<HashMap<String, Object>> table = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> record = new HashMap<String, Object>();
String field1 = "something";
Integer field2 = new Integer(45);
record.put("field1", field1);
record.put ("field2", field2);
table.add(record);
您可以(也许您应该)自动化并使 DTO/DAO 足够灵活以在任何 table 中使用相同的 class,无需硬代码或固定名称。
请记住,您需要为 storing/reading 数据创建包装器和方法,并且这些方法应该是线程安全的。
请记住,只有当您有足够的内存来存储 ResultSet 的所有记录时,此设计才有效。
我正在尝试对结果集进行多线程处理。我想确保每当我在多个线程之一中调用 next()
时,所有其他线程都被锁定。这很重要,因为如果许多线程同时调用 next()
方法,这将导致跳过这些行。这是我做的
public class MainClass {
private static ResultSet rs;
public static void main (String [] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
runWhile();
}});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
runWhile();
}});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.exit(0);
}
private static void runWhile () {
String username = null;
while ((username = getUsername()) != null) {
// Use username to complete my logic
}
}
/**
* This method locks ResultSet rs until the String username is retrieved.
* This prevents skipping the rows
* @return
* @throws SQLException
*/
private synchronized static String getUsername() throws SQLException {
if(rs.next()) {
return rs.getString(1).trim();
}
else
return null;
}
}
这是使用 synchronized
的正确方法吗?它是否锁定 ResutSet
并确保其他线程不干扰?
这是一个好方法吗?
JDBC 对象不应在线程之间共享。这适用于连接、语句和结果集。这里最好的情况是 JDBC 供应商遵循规范并进行内部锁定,这样您就可以解决这个问题,在这种情况下,所有线程仍在尝试获取相同的锁,只有一个可以取得进展一次。这将比使用单个线程慢,因为除了从数据库中读取相同的工作之外,管理所有线程还会产生额外的开销。
(驱动程序完成的锁定可能是为了驱动程序的利益,因此提供商不必处理因用户滥用其软件而导致的竞争条件错误报告。它确实锁定并不一定意味着软件实际上应该被多个线程使用。)
多线程在线程可以同时取得进展时有效,请参阅 Amdahl's Law。如果您遇到可以读取 ResultSet 并使用结果创建提交给 ExecutorService 的任务(正如 Peter Lawrey 在评论中建议的那样),那么这将更有意义(只要这些任务可以独立工作并且不必须互相等待)。
我建议创建结果集,然后将所有数据复制到 DTO(数据传输对象)或 DAO(数据访问对象)中。在 DTO 或 DAO 上获得数据后,关闭您的 ResultSet、Statement 和 Connection。
创建 DTO/DAO 以按顺序存储记录、其字段和解析功能的非常简单的结构是这样的:
ArrayList<HashMap<String, Object>> table = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> record = new HashMap<String, Object>();
String field1 = "something";
Integer field2 = new Integer(45);
record.put("field1", field1);
record.put ("field2", field2);
table.add(record);
您可以(也许您应该)自动化并使 DTO/DAO 足够灵活以在任何 table 中使用相同的 class,无需硬代码或固定名称。
请记住,您需要为 storing/reading 数据创建包装器和方法,并且这些方法应该是线程安全的。
请记住,只有当您有足够的内存来存储 ResultSet 的所有记录时,此设计才有效。