【问题标题】:Java - multiple threads writing to same file [duplicate]Java - 多个线程写入同一个文件[重复]
【发布时间】:2013-10-06 10:32:59
【问题描述】:

我正在尝试通过 Java 中的多个线程将一些内容写入文件。每个线程读取不同的输入文件,进行一些计算并将一些(不同的)内容写入公共输出文件。问题是最后,输出文件只包含最后一个终止线程写入的内容,而不包含来自其他线程的内容。线程的相关代码 -

public void run()
{
    try
    {
        File file = new File("/home/output.txt");
        if (!file.exists()) 
        {
             file.createNewFile();
        }
        FileWriter fw = new FileWriter(file.getAbsoluteFile());
        BufferedWriter bw = new BufferedWriter(fw);

        BufferedReader br = new BufferedReader(new FileReader(inputfile)); // each thread reads a different input file
        String line="";

        while((line=br.readLine())!=null)
        {
            String id = line.trim();               // fetch id

            StringBuffer sb = processId(userId);   // process id

            synchronized(this){
            bw.write(sb.toString() + "\n");        // write to file
            }
        }
        bw.close();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

如何让所有线程将其内容写入公共文件?

【问题讨论】:

  • 您必须附加到现有文件(FileOutputStream 有一个布尔标志)。但是您还必须编写synchronized,以确保同时只有一个线程写入。
  • 如果可以使用StringBuilder就不要使用StringBuffer。在这种情况下 processId() 可以返回一个字符串。
  • 您需要在所有线程中打开文件一次并协调他们的写作。否则你很可能会弄得一团糟。我建议你有一个单线程执行器并向它提交任务以写入文件。这将确保单线程写入。
  • 我正在使用同步块,请查看我的编辑。它还会引起问题吗?

标签: java multithreading


【解决方案1】:

使用 FileWriter 的构造函数,使用追加模式

FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);

【讨论】:

  • 如果 append 为真,字节将被写入文件的末尾而不是开头。所以不用提它,它应该可以工作(因为字节应该写在开头)。我在 OP 中没有看到任何问题。
【解决方案2】:

与您的代码相关的几点:

1. 您创建FileWriter 的方式不正确。如果要将数据附加到文件中,请使用包含额外 boolean 参数的构造函数(使其成为 true):

public FileWriter(File file,boolean append) throws IOException

例如:

FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);

2. 您说的是多个线程将共享一个公共文件,但我在您的代码中看不到任何同步块。使用同步确保一次只有一个线程可以访问共享资源。

【讨论】:

  • 谢谢,请看我的编辑。
  • 嗨,我认为你应该锁定 BufferedWriter 而不是这个。假设有两个名为 Thread-A 和 Thread-B 的线程试图写入文件。现在两者都将尝试在此实例中锁定,但它们应该锁定上述程序中的“bw”共享资源。您对此有何看法?
【解决方案3】:

有一个文件写入线程,它不断从阻塞队列中读取并写入文件。所有其他 20 个线程只会将数据放入阻塞队列。这将防止 20 个编写器线程之间的争用。

【讨论】:

  • 写完所有行后终止线程的最佳方法是什么?
  • 对 writer 使用 newSingleThreadExecutor 并在所有行都写入后将其关闭。
【解决方案4】:

FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);

应该使用表示追加模式。

【讨论】:

    【解决方案5】:

    我是新手。 所以我可能错了!但是您的代码可能会或可能不会起作用。那是 Runnable 还是线程的运行?请注意:

    MyClass implements Runnable {
    
     public void run() {
     ....synchronized(this)..
     }
    
    }
    
    Thread t1 = new Thread(new MyClass());
    Thread t2 = new Thread(new MyClass());
    

    我们中的许多人都这样做(我做到了,做到了:),是的!每个线程都将获得对不同 obj 的锁定,并且您最终可能会得到意想不到的结果,除非操作系统使用某种机制来同步写入同一个文件(我不知道)。如果是这样,那么您的同步是无用的(在我的示例中无论如何都无用),如果不是,那么您很漂亮....另外请注意,可能有另一个使用此 output.txt 的进程,我们没有想法...复杂的东西,至少对我而言

    我的观点是,如果您有 一个 类的实例 SHARESMUTABLESTATE强>。 (让我们暂时忘记同步和静态)

    MyClass 有状态吗?不,它是共享的吗?不,在我的例子中不是。它会起作用吗?不是这样的。大概是这样吧?

    MyClass mc = new MyClass()
    Thread t1 = new Thread(mc);
    Thread t2 = new Thread(mc);
    

    PS:我忘了在每个线程上调用 start。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多