Java File.createNewFile()比FileOutputStream慢得多

Java File.createNewFile()比FileOutputStream慢得多,java,Java,在使用File.createNewFile()或File.createTempFile()时,我观察到一个有趣的性能下降。下面的代码创建48个线程,每个线程将大约128MB的数据写入不同的文件。如果我按原样运行代码,在我的特定机器上大约需要60秒。如果我完全按照原样运行代码,除了注释掉f.createTempFile()调用,那么大约需要5秒钟 import java.util.*; import java.util.concurrent.*; import java.io.File; impo

在使用File.createNewFile()或File.createTempFile()时,我观察到一个有趣的性能下降。下面的代码创建48个线程,每个线程将大约128MB的数据写入不同的文件。如果我按原样运行代码,在我的特定机器上大约需要60秒。如果我完全按照原样运行代码,除了注释掉f.createTempFile()调用,那么大约需要5秒钟

import java.util.*;
import java.util.concurrent.*;
import java.io.File;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public final class TestFile implements Runnable {
  public void run() {
    byte[] b = new byte[128205100];
    Arrays.fill(b, (byte)10);

    try {
      File f = new File("/tmp/test", UUID.randomUUID().toString());

      // If I comment the following f.createNewFile() then the code takes
      // 5 seconds rather than 60 to execute. 
      f.createNewFile();

      FileOutputStream fOutputStream =  new FileOutputStream(f);
      BufferedOutputStream fBufStream = new BufferedOutputStream(fOutputStream, 32768);
      fBufStream.write(b);
      fBufStream.close();
    } catch (IOException e) {
      System.err.println("Caught IOException: " + e.getMessage());
    }
  }

  public static void main(String[] args) {
    final ExecutorService executorPool = Executors.newFixedThreadPool(48);
    for (int counter=0; counter < 48; counter++) {
       executorPool.execute(new TestFile());
    }
    try {
      executorPool.shutdown();
      executorPool.awaitTermination(120, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      System.err.println("Caught InterruptedException: " + e.getMessage());
    }       
  }
}
import java.util.*;
导入java.util.concurrent.*;
导入java.io.File;
导入java.io.BufferedOutputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
公共final类TestFile实现Runnable{
公开募捐{
字节[]b=新字节[128205100];
数组。填充(b,(字节)10);
试一试{
文件f=新文件(“/tmp/test”,UUID.randomUUID().toString());
//如果我对以下f.createNewFile()进行注释,那么代码将
//执行时间为5秒,而不是60秒。
f、 createNewFile();
FileOutputStream fOutputStream=新的FileOutputStream(f);
BufferedOutputStream fBufStream=新的BufferedOutputStream(fOutputStream,32768);
fBufStream.write(b);
fBufStream.close();
}捕获(IOE异常){
System.err.println(“捕获的IOException:+e.getMessage());
}
}
公共静态void main(字符串[]args){
final ExecutorService executorPool=Executors.newFixedThreadPool(48);
用于(int计数器=0;计数器<48;计数器++){
executorPool.execute(新的TestFile());
}
试一试{
executorPool.shutdown();
执行器池。等待终止(120,时间单位。秒);
}捕捉(中断异常e){
System.err.println(“捕获的中断异常:+e.getMessage());
}       
}
}
通过使用jstack,我可以看到,在运行上述代码时,所有线程的大部分时间都花在close0()上。不幸的是,此函数是本机函数:-/知道它的源代码在哪里吗

"Thread-47" #68 prio=5 os_prio=0 tid=0x00007f21001de800 nid=0x4eb4 runnable [0x00007f209edec000]
   java.lang.Thread.State: RUNNABLE
        at java.io.FileOutputStream.close0(Native Method)
        at java.io.FileOutputStream.access$000(FileOutputStream.java:53)
        at java.io.FileOutputStream$1.close(FileOutputStream.java:356)
        at java.io.FileDescriptor.closeAll(FileDescriptor.java:212)
        - locked <0x00000005908ad628> (a java.io.FileDescriptor)
        at java.io.FileOutputStream.close(FileOutputStream.java:354)
        at java.io.FilterOutputStream.close(FilterOutputStream.java:159)
        at TestFile.run(TestFile.java:19)
        at java.lang.Thread.run(Thread.java:745)
“Thread-47”#68优先级=5 os_优先级=0 tid=0x00007f21001de800 nid=0x4eb4可运行[0x00007f209edec000]
java.lang.Thread.State:可运行
位于java.io.FileOutputStream.close0(本机方法)
在java.io.FileOutputStream.access$000(FileOutputStream.java:53)
位于java.io.FileOutputStream$1.close(FileOutputStream.java:356)
位于java.io.FileDescriptor.closeAll(FileDescriptor.java:212)
-锁定(java.io.FileDescriptor)
在java.io.FileOutputStream.close(FileOutputStream.java:354)处
在java.io.FilterOutputStream.close(FilterOutputStream.java:159)处
运行(TestFile.java:19)
运行(Thread.java:745)
我猜某个地方(在本地close0?)有人在发出同步,但我找不到。我已经在一些机器上测试过了,在其中一些机器上我看不到性能下降。因此,这可能是基于配置或环境的

我使用Java8在Ubuntu上运行


任何帮助都将不胜感激。谢谢

这很简单
File.createNewFile()
按该名称搜索一个文件,如果该文件不存在,则创建一个新文件;如果失败,则创建一个新文件,您可以正确忽略该文件,因为成功与否无关紧要
newfileoutputstream()
以相同的名称搜索任何现有文件,将其删除,然后创建一个新文件

因此,很明显,
File.createNewFile()
后面跟着
newfileoutputstream()
,这完全是浪费时间,因为它迫使操作系统:

  • 搜索该文件
  • 如果它不存在或失败,就创建它
  • 搜索该文件
  • 如果存在,请将其删除
  • 创造它
  • 很明显,(1)和(2)是浪费时间,并且迫使(4)在可能不需要的时候发生


    解决方案:在
    newfileoutputstream(…)
    之前不要调用
    File.createNewFile()
    。或者
    新建FileWriter(…)
    ,或者
    新建PrintStream/PrintWriter(…)
    。没有什么可以获得,时间和空间可以浪费。

    这很简单
    File.createNewFile()
    按该名称搜索一个文件,如果该文件不存在,则创建一个新文件;如果失败,则创建一个新文件,您可以正确忽略该文件,因为成功与否无关紧要
    newfileoutputstream()
    以相同的名称搜索任何现有文件,将其删除,然后创建一个新文件

    因此,很明显,
    File.createNewFile()
    后面跟着
    newfileoutputstream()
    ,这完全是浪费时间,因为它迫使操作系统:

  • 搜索该文件
  • 如果它不存在或失败,就创建它
  • 搜索该文件
  • 如果存在,请将其删除
  • 创造它
  • 很明显,(1)和(2)是浪费时间,并且迫使(4)在可能不需要的时候发生


    解决方案:在
    newfileoutputstream(…)
    之前不要调用
    File.createNewFile()
    。或者
    新建FileWriter(…)
    ,或者
    新建PrintStream/PrintWriter(…)
    。没有什么可以获得,时间和空间可以浪费。

    我不能说它为什么会慢那么多,但是,它从
    文件
    参数中使用的只是它的名称和对路径有效性的检查:如果文件已经存在,它会覆盖该文件。因此,没有必要先创建它。同意Turner的观点,createnewfile会检查系统的securityManager,其中作为FileOutputStream只是简单地尝试写入。这不是文件权限问题,因为文件是以相同的权限(rw)创建的。这也不是数据仍然需要刷新的情况,因为如果在fStream.close()之前添加fStream.flush(),会得到相同的行为。谢谢@AndyTurner和nafas。我不认为是安全经理,因为FileO