Java 多线程将同一内容写入同一文件?

Java 多线程将同一内容写入同一文件?,java,synchronized,Java,Synchronized,我一直认为并发线程写入同一个文件需要同步 当多线程在没有同步的情况下将同一内容写入同一文件时会发生什么?我认为输出文件一定不完整或已损坏 public class Test { public Runnable createLayoutRunnable() { return new Runnable() { public void run() { try { FileInputStream inputStr

我一直认为并发线程写入同一个文件需要同步

当多线程在没有同步的情况下将同一内容写入同一文件时会发生什么?我认为输出文件一定不完整或已损坏

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

}

}
公共类测试
{   
公共可运行CreateLayoutRunName(){
返回新的Runnable(){
公开募捐{
试一试{
FileInputStream inputStream=新的FileInputStream(“mov.mp4”);
FileOutputStream outputStream=新的FileOutputStream(“mov_co.mp4”);
//复制(inputStream,outputStream);
//已同步(“锁定”){
int read=0;
字节[]字节=新字节[1024];
而((read=inputStream.read(bytes))!=-1){
outputStream.write(字节,0,读取);
}
//}
System.out.println(Thread.currentThread().getName()+“已完成”);
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
};
}
公共静态void main(字符串[]args){
测试=新测试();
//为并行布局创建线程池
ExecutorService executor=Executors.newFixedThreadPool(9);
//在当前线程中运行任务并等待终止
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());
试一试{
f1.get();
f2.get();
f3.get();
f4.get();
f5.get();
f6.get();
f7.get();
f8.get();
f9.get();
}捕获(例外情况除外){
例如printStackTrace();
}
executor.shutdown();
系统输出打印项次(“全部完成”);
}
}
惊喜!输出mov很好玩! 怎么会?请帮忙


编辑:首先,我对造成的混乱感到非常抱歉。是的,我发布的第一次代码与我所说的是同步的。我现在已经把它评论掉了。这是因为我在玩代码,我发现它是否同步并不重要,我想知道为什么

在您的示例中,即使您取出了同步,每个线程都在将相同的内容写入同一个文件。因为每个线程都使用一个单独的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设置b=2
  • B设a=1
  • A组c=3
  • B组B=2
  • B组c=3
不管有多少线程运行该序列,也不管它们是否被同步,一旦它们完成,{a,b,c}的内容将始终是{1,2,3}(在写入外部文件时有一些警告不适用)。复制一个文件的例子也是如此——输出文件的内容总是相同的;线程中执行的确切顺序并不重要。

在这种特殊情况下,您正在将相同的内容从输入文件写入输出文件中的相同位置。这就是所谓的操作,不管是否同步


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

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

其次,您的代码是同步的,与您所说的相反。你看到同步(“锁定”)部分了吗?起初你说它是不同步的。然后,我们查看代码,发现它是同步的。然后我们认为第一个线程看到的“锁”与另一个线程看到的不同。但它是同一个对象,因为在java中“static string”=“static string”。因此,线程会锁定完整副本。然后另一个来制作完整的副本。当然,播放将不会中断


文件操作中唯一超出同步范围的是文件打开/关闭。(关闭?)在Linux中尝试。这可能会造成很大的不同

当然是这样,您正在同步块中写入文件,但您正在同步。你正在使用一个字符串作为你的锁,这很疯狂,但它仍然在同步。这个字符串在所有线程中都是相同的实例,这是幸运的吗?因为如果它不是同一个实例,他就不会真正同步任何东西。@kutschkem它是同一个实例。(字符串文字是内部的)字符串文字的另一个缺点是java工具无法找到所有的引用来显示锁也被使用的位置。什么?你必须写ABC。第一个线程写AB,第二个线程写AB,然后他们完成写C和C。结果是ABABCC。我认为幂等性是一个专业的词,用来表示严肃和专业。@Val-如果输出流只有一个实例,在线程之间共享,则您是正确的。但这里并不是这样:每个线程有一个实例,每个实例都将启动wri