Java基础--FileDescriptor sync方法

本文详细解析了Java中文件同步的实现方式,特别是在Lucene源码中FSDirectory类的fsync方法。通过实例展示了如何利用FileDescriptor的sync方法确保数据被强制写入物理设备,避免因系统缓冲导致的数据延迟问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在读Lucene的源码过程中,发现FSDirectory类中有一个文件信息同步的方法,对其中的一行代码file.getFD().sync();不是很清楚(这也可见自己的基础有多么的差)。经过一番检索,终于明白了其大意。

  protected void fsync(String name) throws IOException {
    File fullFile = new File(directory, name);
    boolean success = false;
    int retryCount = 0;
    IOException exc = null;
    while (!success && retryCount < 5) {
      retryCount++;
      RandomAccessFile file = null;
      try {
        try {
          file = new RandomAccessFile(fullFile, "rw");
          file.getFD().sync();//强制所有系统缓冲区与基础设备同步
          success = true;
        } finally {
          if (file != null)
            file.close();
        }
      } catch (IOException ioe) {
        if (exc == null)
          exc = ioe;
        try {
          // Pause 5 msec
          Thread.sleep(5);
        } catch (InterruptedException ie) {
          throw new ThreadInterruptedException(ie);
        }
      }
    }
    if (!success)
      // Throw original exception
      throw exc;
  }
}
 
FileDescriptor文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的 FileInputStreamFileOutputStream。 应用程序不应创建自己的文件描述符。
 
大部分人都认为flush后,其他用户应该立即可见。但是在一些极端的情况下也需调用后还是无法看见以写入的数据。
 

flush

   刷新此输出流并强制写出所有缓冲的输出字节。flush 的常规协定是:如果此输出流的实现已经缓冲了以前写入的任何字节,则调用此方法指示应将这些字节立即写入它们预期的目标。

   如果此流的预期目标是由基础操作系统提供的一个抽象(如一个文件),则刷新此流只能保证将以前写入到流的字节传递给操作系统进行写入,但不保证能将这些字节实际写入到物理设备(如磁盘驱动器)。

 OutputStreamflush 方法不执行任何操作。为什么会这样? 原因是,这个缓冲我们java自己实现的。 flush保证的是内部的缓冲写入到系统中。但是系统中文件也可能有缓冲,所以并不一定flush后立即可见。

 那么如何解决这个问题?在文件流或数据流中均可以看见getFD()这个方法, 它返回的是与此流有关的文件描述符。

所以调用文件描述符的sync的方法即可让实际文件强制同步了。JDK中描述如下:

sync

强制所有系统缓冲区与基础设备同步。该方法在此 FileDescriptor 的所有修改数据和属性都写入相关设备后返回。特别是,如果此 FileDescriptor 引用物理存储介质,比如文件系统中的文件,则一直要等到将与此 FileDesecriptor 有关的缓冲区的所有内存中修改副本写入物理介质中,sync 方法才会返回。 sync 方法由要求物理存储(比例文件)处于某种已知状态下的代码使用。例如,提供简单事务处理设施的类可以使用 sync 来确保某个文件所有由给定事务造成的更改都记录在存储介质上。 sync 只影响此 FileDescriptor 的缓冲区下游。如果正通过应用程序(例如,通过一个 BufferedOutputStream 对象)实现内存缓冲,那么必须在数据受 sync 影响之前将这些缓冲区刷新,并转到 FileDescriptor 中(例如,通过调用 OutputStream.flush)。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28624388/viewspace-763524/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28624388/viewspace-763524/

"shortcutservice" prio=5 tid=200 Native | group="main" sCount=1 ucsCount=0 flags=1 obj=0x17560118 self=0xb400006fda2d2400 | sysTid=8169 nice=0 cgrp=ssfg sched=0/0 handle=0x6ff38f1730 | state=S schedstat=( 157157722 3434221361 1501 ) utm=3 stm=11 core=5 HZ=100 | stack=0x6ff37ee000-0x6ff37f0000 stackSize=1037KB | held mutexes= native: #00 pc 000b9cd0 /apex/com.android.runtime/lib64/bionic/libc.so (syscall+32) (BuildId: a3cde331295ff116d9c0d5e2198af1eb) native: #01 pc 0048f7a8 /apex/com.android.art/lib64/libart.so (art::ConditionVariable::WaitHoldingLocksWithInfo+160) (BuildId: 933ac9f8face98d6497ff39053c286bc) native: #02 pc 00c18448 /apex/com.android.art/lib64/libart.so (artJniMethodEnd+408) (BuildId: 933ac9f8face98d6497ff39053c286bc) native: #03 pc 007232bc /apex/com.android.art/lib64/libart.so (art_jni_method_end+12) (BuildId: 933ac9f8face98d6497ff39053c286bc) at java.io.FileDescriptor.sync(Native method) at android.os.FileUtils.sync(FileUtils.java:279) at com.android.server.pm.ResilientAtomicFile.finalizeOutStream(ResilientAtomicFile.java:64) at com.android.server.pm.ResilientAtomicFile.finishWrite(ResilientAtomicFile.java:145) at com.android.server.pm.ShortcutPackageItem.saveToFileLocked(ShortcutPackageItem.java:182) at com.android.server.pm.ShortcutPackageItem.saveShortcutPackageItem(ShortcutPackageItem.java:226) - locked <0x08628dd1> (a java.lang.Object) at com.android.server.pm.ShortcutPackageItem$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) at android.os.Handler.handleCallback(Handler.java:973) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:282) at android.os.Looper.loop(Looper.java:387) at android.os.HandlerThread.run(HandlerThread.java:85) DumpLatencyMs: 1290.67查找线程200,怎么分析
最新发布
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值