首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8流和并发写入

Java 8流和并发写入
EN

Stack Overflow用户
提问于 2015-08-18 08:52:10
回答 2查看 1.8K关注 0票数 0

我有这样的代码

代码语言:javascript
复制
    public static void main(String[] args) throws Exception {
      long start = System.currentTimeMillis();
      List<String> matches = new Vector<>(); // Race condition for ArrayList??
      BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("AHugeFile.txt")));
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("output.txt")));
      reader.lines().parallel()
         .filter(s -> s.matches("someFancyRegEx"))
         .forEach(s -> {
               matches.add(s);
               try {
                  writer.write(s);
                  writer.newLine();
               } catch (Exception e) {
                  System.out.println("error");
               }
            }
         );
      out.println("Processing took " + (System.currentTimeMillis() - start) / 1000 + " seconds and matches " + matches.size());
      reader.close();
      writer.flush();
      writer.close();
   }

我注意到,如果在第3行用ArrayList替换Vector,那么每次匹配都会得到不同的结果。我只是想在流上弄脏我的手,但是假设forEach同时执行,试图写到ArrayList,而ArrayList漏掉了一些写!对于向量,结果是一致的。

我有两个问题:

  1. 我对ArrayList引起比赛的推理正确吗?
  2. 考虑到“写”也是在同一个终端操作中写入文件,“写”可能会遗漏一些行吗?在我的测试中,运行程序几次,结果似乎与所写出的正确行数一致。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-08-18 08:56:26

  1. ArrayList不是一个同步的集合,所以是的,它会导致争用条件。更改向量状态的所有方法都是同步的,因此您在那里没有发现任何问题。
  2. BufferedWriter的写方法是同步的,所以所有的写在线程之间都是一致的。因此,文件中的单个写入操作将是线程安全的。但是,您需要显式地处理同步,以使其在线程之间保持一致。

以下是Java 6中写方法的代码片段。

代码语言:javascript
复制
public void write(String s, int off, int len) throws IOException {

    synchronized (lock) {

        ensureOpen();

        int b = off, t = off + len;

        while (b < t) {

            int d = min(nChars - nextChar, t - b);
            s.getChars(b, b + d, cb, nextChar);
            b += d;
            nextChar += d;

            if (nextChar >= nChars)
                flushBuffer();
            }
        }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2015-08-18 09:32:36

首先要做的是:定义您是否关心写行的顺序; (been there, done that)

第二:使用Java 8提供的工具;它有两个非常方便的方法,即Files.lines()Files.write()

第三:正确处理你的资源!在您的代码中不能保证文件描述符将正确关闭。

第四:.matches()每次都会重新创建一个Pattern,您总是使用相同的正则表达式进行过滤.你在浪费资源。

第五:考虑到BufferedWriter的写方法是同步的,那么并行性不会带来什么好处。

我会这样做:

代码语言:javascript
复制
public static void writeFiltered(final Path srcFile, final Path dstFile,
    final String regex)
    throws IOException
{
    final Pattern pattern = Pattern.compile(regex);

    final List<String> filteredLines;

    try (
        // UTF-8 by default
        final Stream<String> srcLines = Files.lines(srcFile);
    ) {
        filteredLines = srcLines.map(pattern::matcher)
            .filter(Matcher::matches)
            .collect(Collectors.toList());
    }

    // UTF-8 by default
    Files.write(dstFile, filteredLines);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32067786

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档