多线程将同一个东西写入同一个文件?

时间:2013-05-23 15:01:02

标签: java synchronized

我总是认为同时写入同一个文件的线程需要同步。

多线程在没有同步的情况下将相同的内容写入同一文件时会发生什么?我想象输出文件必须不完整或已损坏。

public class Test 
{   
  public Runnable createLayoutRunnable() {
    return new Runnable() {
        public void run() {
            try {
                FileInputStream inputStream = new FileInputStream("mov.mp4");

                FileOutputStream outputStream = new FileOutputStream("mov_co.mp4");
                //IOUtils.copy(inputStream, outputStream);

                //synchronized ("lock"){
                int read = 0;
                byte[] bytes = new byte[1024];

                while ((read = inputStream.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
                //}

                System.out.println(Thread.currentThread().getName() + " is done"); 



            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
}


public static void main(String[] args) {
    Test test = new Test();
    //Create Thread Pool for parallel layout
    ExecutorService executor = Executors.newFixedThreadPool(9);

    //Run Tasks and wait for termination in the current thread
    Future<?> f1 = executor.submit(test.createLayoutRunnable());
    Future<?> f2 = executor.submit(test.createLayoutRunnable());
    Future<?> f3 = executor.submit(test.createLayoutRunnable());
    Future<?> f4 = executor.submit(test.createLayoutRunnable());
    Future<?> f5 = executor.submit(test.createLayoutRunnable());
    Future<?> f6 = executor.submit(test.createLayoutRunnable());
    Future<?> f7 = executor.submit(test.createLayoutRunnable());
    Future<?> f8 = executor.submit(test.createLayoutRunnable());
    Future<?> f9 = executor.submit(test.createLayoutRunnable());


    try {
        f1.get();
        f2.get();
        f3.get();
        f4.get();
        f5.get();
        f6.get();
        f7.get();
        f8.get();
        f9.get();


    } catch (Exception ex) {
        ex.printStackTrace();
    }
    executor.shutdown();

    System.out.println("all done");

}

}

惊喜!输出mov很好玩! 怎么会?请帮忙!

编辑:最重要的是,我对这种困惑非常抱歉。是的,我发布的第一次代码是同步的,而不是我说的。我现在评论过了。这是因为我正在使用代码,而这就是我发现它是否同步无关紧要并且想知道为什么。

3 个答案:

答案 0 :(得分:3)

在此特定的情况下,您将输入文件中的相同内容写入输出文件中的相同位置。这就是所谓的idempotent操作,无论您是否同步都无关紧要。

如果每个线程编写了自己的源文件(并且您消除了同步),您会看到(1)一个线程将获胜,或者(2,更可能)您将获得交错(损坏)内容。 / p>

答案 1 :(得分:2)

在您的示例中,即使您取出同步,每个线程也会将相同的内容写入同一文件。因为每个线程使用单独的OutputStream(和InputStream),所以线程不会干扰彼此的文件位置。因此输出是输入文件的副本。

它类似于:

public static int a;
public static int b;
public static int c;

使用线程代码:

a = 1;
b = 2;
c = 3;

想象一下,你有两个线程,A和B.执行顺序可能如下,例如:

  • A设置a = 1;
  • A set b = 2;
  • B设a = 1;
  • A set c = 3;
  • B设b = 2;
  • B设c = 3;

运行该序列的线程数量也不重要,也不管它们是否同步,一旦完成,{a,b,c}的内容将始终为{1,2,3}(有一些警告)写入外部文件时不适用)。复制文件的示例与此相同 - 输出文件的内容始终相同;线程中执行的确切顺序并不重要。

答案 2 :(得分:2)

多线程访问并不意味着你会得到垃圾。这意味着结果是不可预测的。有些系统可能只是自己同步,结果可能看起来像是在互斥锁下访问的。

其次,您的代码已同步,而不是您所说的。你看到那个部分同步(“锁定”)?首先你说它不同步。然后,我们查看代码并看到它是同步的。然后我们认为第一个线程可见的“锁定”与另一个线程看到的不同。但它是同一个对象,因为在java“静态字符串”==“静态字符串”。因此,该线程使完整副本处于锁定状态。然后另一个来,并制作完整的副本。当然,播放将不会中断。

文件操作中唯一的外部同步是文件打开/关闭。 (关闭?)在Linux中试试。这可能会产生很大的不同。