是否同步锁定结果集对象?

时间:2016-05-31 17:38:43

标签: java multithreading jdbc 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并确保其他线程不会干扰吗?

这是一个好方法吗?

2 个答案:

答案 0 :(得分:5)

不应在线程之间共享JDBC对象。这适用于Connections,Statements和ResultSet。这里最好的情况是JDBC供应商遵循规范并进行内部锁定,以便您可以使用它,在这种情况下,所有线程仍然尝试获取相同的锁,并且只有一个可以一次进行。这比使用单个线程要慢,因为除了从数据库执行相同的工作之外,管理所有线程还有额外的开销。

(由驱动程序完成的锁定可能是为了驱动程序的利益,因此提供程序不必处理因用户滥用其软件而导致的竞争条件的错误报告。它确实锁定并不一定意味着软件应该实际上是由多个线程使用。)

当线程可以同时进行时,多线程工作,请参阅Amdahl's Law。如果您有可以阅读ResultSet并使用结果来创建您提交给ExecutorService的任务的情况(正如Peter Lawrey在评论中所建议的那样)那么这将更有意义(只要这些任务可以独立工作并且不要不得不互相等待。

答案 1 :(得分:0)

我建议创建ResultSet,然后将所有数据复制到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足够灵活,可以在任何表中使用相同的类,而无需硬编码或固定名称。

请记住,您需要创建一个包装器以及存储/读取数据的方法,并且这些方法应该是线程安全的。

请记住,只有当您有足够的内存来存储ResultSet的所有记录时,此设计才有效。