-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
6u24
-
x86
-
linux
FULL PRODUCT VERSION :
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux herl26 2.6.18-194.11.1.el5 #1 SMP Tue Jul 27 05:45:06 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
>cat /etc/redhat-release
Red Hat Enterprise Linux Client release 5.5 (Tikanga)
EXTRA RELEVANT SYSTEM CONFIGURATION :
>cat /etc/redhat-release
Red Hat Enterprise Linux Client release 5.5 (Tikanga)
File system is ext3 mounted with (rw) flags:
/dev/mapper/VolGroup00-LogVol00 on / type ext3 (rw)
A DESCRIPTION OF THE PROBLEM :
The lock() method of java.nio.FileChannel is documented to return a java.nio.FileLock indicating the lock that was obtained when the method completes. It also throws a number of different exceptions indicating various problems that might occur in obtaining the lock.
If FileChannel.lock() is called on a thread which is interrupted, the return value of the method is null and no exception is thrown. This is inconsistent with the documentation, which says that a lock object is returned. Instead, probably an AsynchronousCloseException or a ClosedByInterruptException should be thrown, as other FileChannel methods do in this case (I have checked this for truncate()).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test case. It is a class with a main method that can be called with no arguments.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The test program should finish normally, within a few seconds, with no errors.
ACTUAL -
After a (varying) number of loops, the test program prints an error. Example output:
At loop 100
At loop 200
At loop 300
lockerThread at loop 365: java.lang.NullPointerException: Returned lock is null
java.lang.NullPointerException: Returned lock is null
at LockInterruptor.lock(LockInterruptor.java:97)
at LockInterruptor.run(LockInterruptor.java:61)
at java.lang.Thread.run(Thread.java:662)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
See actual result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.List;
/**
* Test class to expose FileChannel.lock behaviour. This method may return null
* if the thread on which it is called is interrupted. This is undocumented
* behaviour.
*
* @author Paul Balm - ###@###.###
*/
public class LockInterruptor implements Runnable {
private final int MAX_LOOPS = 10*1000;
public static void main(String[] args) throws InterruptedException {
LockInterruptor worker = new LockInterruptor();
worker.start();
}
/**
* Start one thread performing the {@link #run()} method of this class. Then
* interrupt that thread. The thread will
* throw a NullPointerException indicating the erroneous behaviour of
* FileChannel#lock.
*
* @throws InterruptedException
*/
public void start() throws InterruptedException {
Thread thread = new Thread(this, "lockerThread");
thread.start();
Thread.sleep(100);
thread.interrupt();
Thread.sleep(1000);
}
/**
* This method creates files and locks them. When the thread is interrupted,
* the files are cleaned up.
* <p>
* If the FileChannel#lock method returns null, which it should never, this
* method throws a NullPointerException.
*/
@Override
public void run() {
List<File> files = new ArrayList<File>();
int i = 0;
Exception badException = null;
try {
while (i < MAX_LOOPS) {
File file = File.createTempFile("FileChannelTest-", ".bin");
files.add(file);
lock(file);
if (++i % 100 == 0) {
System.out.println("At loop " + i);
}
}
} catch (ClosedChannelException e) {
// This one would be ok though it's not actually thrown in practice
} catch (IOException e) {
badException = e;
} catch (RuntimeException e) {
badException = e;
} finally {
cleanUp(files);
}
if (badException != null) {
String name = Thread.currentThread().getName();
System.out.println(name + " at loop " + i + ": "
+ badException.getClass().getName() + ": "
+ badException.getMessage());
badException.printStackTrace();
}
}
/**
* Use FileChannel#lock to lock the passed file. Throw a
* NullPointerException if FileChannel#lock returned null.
*/
private void lock(File file) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
FileChannel channel = fos.getChannel();
FileLock lock = channel.lock();
if (lock == null) {
throw new NullPointerException("Returned lock is null");
}
}
/**
* Delete the list of files.
*/
private void cleanUp(List<File> files) {
for (File file : files) {
if (file.exists()) {
file.delete();
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The developer has to be aware that null can be returned from FileChannel.lock() and test for this.
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux herl26 2.6.18-194.11.1.el5 #1 SMP Tue Jul 27 05:45:06 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
>cat /etc/redhat-release
Red Hat Enterprise Linux Client release 5.5 (Tikanga)
EXTRA RELEVANT SYSTEM CONFIGURATION :
>cat /etc/redhat-release
Red Hat Enterprise Linux Client release 5.5 (Tikanga)
File system is ext3 mounted with (rw) flags:
/dev/mapper/VolGroup00-LogVol00 on / type ext3 (rw)
A DESCRIPTION OF THE PROBLEM :
The lock() method of java.nio.FileChannel is documented to return a java.nio.FileLock indicating the lock that was obtained when the method completes. It also throws a number of different exceptions indicating various problems that might occur in obtaining the lock.
If FileChannel.lock() is called on a thread which is interrupted, the return value of the method is null and no exception is thrown. This is inconsistent with the documentation, which says that a lock object is returned. Instead, probably an AsynchronousCloseException or a ClosedByInterruptException should be thrown, as other FileChannel methods do in this case (I have checked this for truncate()).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test case. It is a class with a main method that can be called with no arguments.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The test program should finish normally, within a few seconds, with no errors.
ACTUAL -
After a (varying) number of loops, the test program prints an error. Example output:
At loop 100
At loop 200
At loop 300
lockerThread at loop 365: java.lang.NullPointerException: Returned lock is null
java.lang.NullPointerException: Returned lock is null
at LockInterruptor.lock(LockInterruptor.java:97)
at LockInterruptor.run(LockInterruptor.java:61)
at java.lang.Thread.run(Thread.java:662)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
See actual result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.List;
/**
* Test class to expose FileChannel.lock behaviour. This method may return null
* if the thread on which it is called is interrupted. This is undocumented
* behaviour.
*
* @author Paul Balm - ###@###.###
*/
public class LockInterruptor implements Runnable {
private final int MAX_LOOPS = 10*1000;
public static void main(String[] args) throws InterruptedException {
LockInterruptor worker = new LockInterruptor();
worker.start();
}
/**
* Start one thread performing the {@link #run()} method of this class. Then
* interrupt that thread. The thread will
* throw a NullPointerException indicating the erroneous behaviour of
* FileChannel#lock.
*
* @throws InterruptedException
*/
public void start() throws InterruptedException {
Thread thread = new Thread(this, "lockerThread");
thread.start();
Thread.sleep(100);
thread.interrupt();
Thread.sleep(1000);
}
/**
* This method creates files and locks them. When the thread is interrupted,
* the files are cleaned up.
* <p>
* If the FileChannel#lock method returns null, which it should never, this
* method throws a NullPointerException.
*/
@Override
public void run() {
List<File> files = new ArrayList<File>();
int i = 0;
Exception badException = null;
try {
while (i < MAX_LOOPS) {
File file = File.createTempFile("FileChannelTest-", ".bin");
files.add(file);
lock(file);
if (++i % 100 == 0) {
System.out.println("At loop " + i);
}
}
} catch (ClosedChannelException e) {
// This one would be ok though it's not actually thrown in practice
} catch (IOException e) {
badException = e;
} catch (RuntimeException e) {
badException = e;
} finally {
cleanUp(files);
}
if (badException != null) {
String name = Thread.currentThread().getName();
System.out.println(name + " at loop " + i + ": "
+ badException.getClass().getName() + ": "
+ badException.getMessage());
badException.printStackTrace();
}
}
/**
* Use FileChannel#lock to lock the passed file. Throw a
* NullPointerException if FileChannel#lock returned null.
*/
private void lock(File file) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
FileChannel channel = fos.getChannel();
FileLock lock = channel.lock();
if (lock == null) {
throw new NullPointerException("Returned lock is null");
}
}
/**
* Delete the list of files.
*/
private void cleanUp(List<File> files) {
for (File file : files) {
if (file.exists()) {
file.delete();
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The developer has to be aware that null can be returned from FileChannel.lock() and test for this.
- duplicates
-
JDK-6979009 (fc) FileChannel.read() fails to throw ClosedByInterruptException
-
- Closed
-