FileEditor2.java - Avoiding FileNotFoundException

This section describes a revised thread productivity testing program, FileEditor2.java, that repeats a work unit of reading data from a file and write it back to a different file to avoid the FileNotFoundException bug.

When searching for answer on the "java.io.FileNotFoundException: FileEditor.dat (The requested operation cannot be performed on a file with a user-mapped section open)" issue, I saw reports saying that it is related a known HotSpot JVM bug opened in 2002. Here is the summary of the bug:

DK-4724038 : (fs) Add unmap method to MappedByteBuffer

Details
Type: Enhancement
Submit Date: 2002-07-31
Status: Open
Updated Date: 2013-11-20
Project Name: JDK
Resolved Date:
Component: core-libs
OS: windows_vista,solaris_8,generic,windows_2000
Sub-Component: java.nio
CPU: x86,generic
Priority: P4
Resolution: Unresolved
Affected Versions: 1.4.0,5.0,7
Targeted Versions:

...
Description
Name: nt126004			Date: 07/31/2002

FULL PRODUCT VERSION : java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Once a file has been mapped a number of operations on that
file will fail until the mapping has been released (e.g.
delete, truncating to a size less than the mapped area).
However the programmer can't control accurately the time at
which the unmapping takes place --- typically it depends on
the processing of finalization or a PhantomReference queue.

The danger associated with unmapping that is noted in the
JavaDoc could be avoided if when an area is unmapped, the
memory is not made available for reallocation but instead
is reserved (e.g. by using VirtualAlloc under Windows).
Then any unwanted reference to the previously mapped area
would result in an exception without incurring performance
penalties. The finalization process could release the
reservation when there were no remaining references to the
buffer.

...

As we can see from the bug document, the bug was opened in 2002, and remained open until today. I am not sure why Sun and Oracle can not fix the issue.

So, to avoid this issue, I revised my thread class to FileEditor2.java, which reads data from a file and write it back to different file repeatedly:

/* FileEditor2.java
 * Avoiding using the same file repeatedly
 * Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
import java.io.*;
import java.util.*;
public class FileEditor2 extends Thread {
   public int fileSize; // The size of the file to work on
   public String fileName; // The name of the file
   public long jobCount; // The number of jobs done so far
   public int myCheckSum; // The checksum of the file
   public int firstByte; // The first byte of the file
   public long seqID; // A sequence ID
   public static void main(String[] a) {
      int size = 1000;
      String name = "FileEditor.dat";
      long interval = 1; // Monitoring interval in seconds
      if (a.length>0) size = Integer.parseInt(a[0]);
      if (a.length>1) name = a[1];
      System.out.println("File size: "+size);

      // Initializing the data file
      byte[] data = new byte[size];
      Random r = new Random();
      r.nextBytes(data);
      try {
         FileOutputStream fos = new FileOutputStream(name);
         fos.write(data);
         fos.close();
      } catch (Exception e) {
      	 e.printStackTrace();
      	 return;
      }
      
      FileEditor2 t = new FileEditor2(size, name);
      t.start();
      int i = 0;
      long startTime = System.currentTimeMillis();
      System.out.println(
         "Time, Count, Productivity, CheckSum, firstByte");
      while (true) {
         try {
            sleep(interval*1000);
         } catch (InterruptedException e) {
            System.out.println("Monitor interrupted.");
         }
         long curTime = System.currentTimeMillis();
         long duration = (curTime - startTime)/1000;
         long productivity = t.jobCount/duration;
         System.out.println(duration+", "+t.jobCount
            +", "+productivity+", "+t.myCheckSum+", "+t.firstByte);
      }
   }
   public FileEditor2(int size, String name) {
      fileSize = size;
      fileName = name;
      jobCount = 0;
      myCheckSum = 0;
      firstByte = 0;
      seqID = 0;
   }
   private long nextSeqID() {
      seqID++;
      return seqID;
   }
   public void run() {
      byte[] buffer = new byte[fileSize];
      String oldName = fileName;
      String newName = fileName+"_"+nextSeqID();
      try {
         while (true) {
            FileInputStream fis = new FileInputStream(oldName);
            int bytes = fis.read(buffer);
            fis.close();
            long sum = 0;
            for (int i=0; i<fileSize; i++) {
                sum = (sum+(buffer[i]&0x00FF))%Integer.MAX_VALUE;
            }
            myCheckSum = (int)sum;
            firstByte = buffer[0]&0x00FF;
            FileOutputStream fos = new FileOutputStream(newName);
            fos.write(buffer,1,fileSize-1);
            fos.write(buffer,0,1);
            fos.close();
            
            (new File(oldName)).delete();
            oldName = newName;
            newName = fileName+"_"+nextSeqID();
            jobCount++;
         }
      } catch (Exception e) {
      	 e.printStackTrace();
      	 return;
      }     
   }
}

Run it with a file size of 4 to verify its correctness:

C:\>"\Program Files\java\jdk1.7.0_45\bin\javac" FileEditor2.java

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" FileEditor2 4
File size: 4
Time, Count, Productivity, CheckSum, firstByte
1, 1219, 1219, 288, 12
2, 2422, 1211, 288, 81
3, 3713, 1237, 288, 3
4, 4898, 1224, 288, 81
5, 6214, 1242, 288, 81
6, 7459, 1243, 288, 12
7, 8330, 1190, 288, 81
8, 9332, 1166, 288, 192
9, 10676, 1186, 288, 192
10, 11975, 1197, 288, 12
...

Now try it with a file size of 10 for a long time to see if we are still getting that exceptions:

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" FileEditor2 10
File size: 10
Time, Count, Productivity, CheckSum, firstByte
1, 1219, 1219, 288, 12
...
156, 135524, 868, 1178, 10
157, 136251, 867, 1178, 120
158, 137176, 868, 1178, 43
159, 138112, 868, 1178, 202
160, 139069, 869, 1178, 163
161, 139834, 868, 1178, 18
162, 140802, 869, 1178, 202

Okay, looks like as have avoided the FileNotFoundException bug.

Last update: 2014.

Table of Contents

 About This Book

 Downloading and Installing JDK 1.8.0 on Windows

 Downloading and Installing JDK 1.7.0 on Windows

 java.lang.Runtime Class - The JVM Instance

 java.lang.System Class - The Operating System

 ClassLoader Class - Class Loaders

 Class Class - Class Reflections

 Sun's JVM - Java HotSpot VM

 JRockit JVM 28.2.7 by Oracle Corporation

 JVM Runtime Data Areas

 Memory Management and Garbage Collectors

 Garbage Collection Tests

 JVM Stack, Frame and Stack Overflow

 Thread Testing Program and Result

 CPU Impact of Multi-Thread Applications

I/O Impact of Multi-Thread Applications

 FileEditor.java - I/O Intensive Process

FileEditor2.java - Avoiding FileNotFoundException

 MultithreadingIoRunner.java - Multiple I/O Threads

 Running Multiple I/O Threads on JRockit

 CDS (Class Data Sharing)

 Micro Benchmark Runner and JVM Options

 Micro Benchmark Tests on "int" Operations

 Micro Benchmark Tests on "long" Operations

 Micro Benchmark Tests in JIT Compilation Mode

 Micro Benchmark Tests on "float" and "double" Operations

 Outdated Tutorials

 References

 PDF Printing Version