简体   繁体   English

多线程将同一事物写入同一文件?

[英]Multi-threads writing same thing to the same file?

I alway thought concurrently threads writing to one same file needs synchronization. 我一直认为并发写入同一文件的线程需要同步。

What happend when multi-threads writing same thing to the same file without synchronization? 当多线程在不同步的情况下将同一事物写入同一文件时会发生什么? I imagined the output file must be incomplete or corrupted. 我以为输出文件必须不完整或损坏。

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");

}

}

Surprise! 惊喜! The output mov is good to play! 输出mov很好玩! How come? 怎么会? Please help! 请帮忙!

Edit: Before all, I'm terribly sorry about the confusion. 编辑:毕竟,我对此感到非常抱歉。 Yes the first-time code I posted was synchronised as opposed to what I said. 是的,我发布的首次代码是同步的,而不是我所说的。 I have commented it off now. 我现在已经评论掉了。 This is because I was playing with the code and that's where I found whether it's synchronised or not doesn't matter and was wondering why. 这是因为我正在使用代码,并且在那儿我发现它是否同步并不重要,并且想知道为什么。

In this particular case, you're writing identical content from an input file to identical locations in an output file. 在这种特殊情况下,你写从一个输入文件中相同位置的输出文件相同的内容。 This is what's called an idempotent operation, and it doesn't matter whether you synchronize or not. 这就是所谓的幂等操作,无论是否同步,都无关紧要。

If each thread wrote its own source file (and you eliminated synchronization), you'd see that either (1) one thread would win, or (2, more likely) you'd get interleaved (corrupted) content. 如果每个线程都编写了自己的源文件(并且消除了同步),您会看到(1)一个线程将获胜,或者(2,更有可能)您获得交错(损坏)的内容。

In your example, even if you took out the synchronisation, each thread is writing the same content to the same file. 在您的示例中,即使您进行了同步,每个线程也将相同的内容写入相同的文件。 Because each thread is using a separate OutputStream (and InputStream) the threads do not interfere with each other's file position. 因为每个线程都使用单独的OutputStream(和InputStream),所以线程不会互相干扰文件的位置。 Thus the output is a copy of the input file. 因此,输出是输入文件的副本。

It's analogous to this: 与此类似:

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

With the threaded code being: 线程代码为:

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

Imagine you have two threads, A and B. The sequence of execution might run as follows, for example: 假设您有两个线程A和B。执行顺序可能如下运行,例如:

  • A sets a = 1; A设定a = 1;
  • A sets b = 2; A集合b = 2;
  • B sets a = 1; B设置a = 1;
  • A sets c = 3; 一组c = 3;
  • B sets b = 2; B设置b = 2;
  • B sets c = 3; B设置c = 3;

It doesn't matter how many threads run that sequence nor whether they are synchronised, once they are finished the contents of {a,b,c} will always be {1,2,3} (with some caveats that don't apply when writing to an external file). 无论有多少个线程运行该序列,也无论它们是否同步,都无关紧要,一旦完成,{a,b,c}的内容将始终为{1,2,3}(有些警告不适用)写入外部文件时)。 It's the same with your example copying a file - the contents of the output file are always the same; 复制示例与您的示例相同-输出文件的内容始终相同; the exact sequence of execution in the threads doesn't matter. 线程中的确切执行顺序无关紧要。

Multithreaded access does not mean that you will get garbage. 多线程访问并不意味着您将获得垃圾。 It means that result is inpredictable . 这意味着结果是不可预测的 Some systems may just synchronize something themselves and result may seem like it is accessed under mutex. 某些系统可能只是自己同步了某些内容,结果似乎是在互斥锁下对其进行了访问。

Secondly, your code is synchronized , as opposed to what you say. 其次, 您的代码是同步的 ,而不是您所说的。 Do you see that section sync("lock")? 您是否看到该部分sync(“ lock”)? At first you say that it is not synchronized. 首先,您说它不同步。 Then, we look into the code and see that it is synchronized. 然后,我们查看代码并看到它已同步。 Then we think that "lock", visible to the first thread is different from what another sees. 然后,我们认为第一个线程可见的“锁”与另一个线程看到的不同。 But it is the same object because in java "static string" == "static string". 但这是同一对象,因为在Java中,“静态字符串” ==“静态字符串”。 So, the thread makes the full copy under lock. 因此,线程使完整副本处于锁定状态。 Then another comes and makes the full copy. 然后另一个来制作完整副本。 Sure, the playback will be uninterrupted. 当然,播放将不会中断。

The only thing in file manipulation that goes outside synchronization is file open/close. 文件操作中唯一超出同步的是文件打开/关闭。 (close?) Try in Linux. (关闭?)在Linux中尝试。 This may make a big difference there. 这可能会带来很大的不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM