缓冲读卡器和优先级队列一起工作?

时间:2012-03-24 21:30:04

标签: java sql multithreading buffer thread-priority

我正在处理一个从.csv文件中读取项目的程序,并将它们写入远程数据库。我正在尝试多线程程序,为此我创建了2个具有不同连接的进程线程。为此,将.csv文件读入缓冲读取器,并处理缓冲读取器的内容。但是,似乎线程不断复制数据(将每个元组的两个副本写入数据库)。

我一直在试图弄清楚如何在Java中使用mutex缓冲区,而我最接近的就是优先级队列。

我的问题是,您是否可以使用缓冲读卡器逐行将文件读入优先级队列?即。

public void readFile(Connection connection) {
        BufferedReader bufReader = null;
        try{
            bufReader = new BufferedReader(new FileReader(RECS_FILE));
            bufReader.readLine(); //skip header line
            String line;
            while((line = bufReader.readLine()) != null) {
                //extract fields from each line of the RECS_FILE
                Pattern pattern = Pattern.compile( "\"([^\"]+)\",\"([^\"]+)\",\"([^\"]+)\",\"([^\"]+)\"");
                Matcher matcher = pattern.matcher(line); 
                if(!matcher.matches()) {
                    System.err.println("Unexpected line in "+RECS_FILE+": \""+line+"\"");
                    continue;
                }
                String stockSymbol = matcher.group(1);
                String recDateStr = matcher.group(2);
                String direction = matcher.group(3);
                String completeUrl = matcher.group(4);

                //create recommendation object to populate required fields
                //  and insert it into the database
                System.out.println("Inserting to DB!");
                Recommendation rec = new Recommendation(stockSymbol, recDate, direction, completeUrl);
                rec.insertToDb(connection);
            }
        } catch (IOException e) {
            System.err.println("Unable to read "+RECS_FILE);
            e.printStackTrace();
        } finally {
            if(bufReader != null) {
                try{
                    bufReader.close();
                } catch (IOException e) {
                }
            }
        }

    }

您将看到使用缓冲读取器读取.csv文件。有没有办法在函数外部设置优先级队列,以便缓冲的读取器将元组放入优先级队列,然后每个程序线程访问优先级队列?

2 个答案:

答案 0 :(得分:1)

缓冲读者,或者实际上任何读者或流本质上仅用于单线程使用。优先级队列是一个完全独立的结构,根据实际的实现,可能会或可能不会被多个线程使用。所以简短的回答是:不,它们是两个完全不相关的概念。

解决原始问题:您无法使用多线程的流式文件访问。您理论上可以使用RandomAccessFile,但您的线条不是固定宽度,因此在不读取文件中的所有内容之前,您不能seek()到行的开头。此外,即使您的数据由固定的记录组成,读取具有两个不同线程的文件也可能是不切实际的。

唯一可以并行化的是数据库插入,明显需要注意的是丢失了事务性,因为必须为每个线程使用单独的事务。 (如果不这样做,则必须同步数据库操作,这再次意味着您没有赢得任何东西。)

因此,解决方案可以是从一个线程读取行并将字符串传递给通过ExecutorService调用的处理方法。这样可以很好地扩展,但是有一点需要注意:增加数据库锁定的开销可能会使使用多个线程的优势无效。

最终的教训可能不是过于复杂化:尝试简单的方法,只有在简单的方法不起作用时才寻找更复杂的解决方案。另一个教训可能是多线程不能帮助I / O绑定程序。

答案 1 :(得分:0)

@ Biziclop的回答是(+1),但我想我会添加一些关于批量数据库插入的内容。

如果您不知道,在大多数SQL数据库中关闭数据库自动提交是批量插入过程中的一大胜利。通常在每个SQL语句之后,数据库将其提交到磁盘存储,磁盘存储更新索引并对磁盘结构进行所有更改。通过关闭此自动提交,数据库只需在最后调用commit时进行这些更改。通常你会做类似的事情:

conn.setAutoCommit(false);
for (Recommendation rec : toBeInsertedList) {
    rec.insertToDb(connection);
}
conn.setAutoCommit(true);

此外,如果数据库不支持自动提交,通常在事务中包装插入也会完成同样的事情。

以下是另一些可能有用的答案: