简体   繁体   中英

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! 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.

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. 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 sets a = 1;
  • A sets b = 2;
  • B sets a = 1;
  • A sets c = 3;
  • B sets b = 2;
  • B sets 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). 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")? 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". 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. This may make a big difference there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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