RandomAccessFile file = null; // The file we'll lock
FileChannel f = null; // The channel to the file
FileLock lock = null; // The lock object we hold
try { // The finally clause closes the channel and releases the lock
// We use a temporary file as the lock file.
String tmpdir = System.getProperty("java.io.tmpdir");
String filename = Lock.class.getName()+ ".lock";
File lockfile = new File(tmpdir, filename);
// Create a FileChannel that can read and write that file.
// Note that we rely on the java.io package to open the file,
// in read/write mode, and then just get a channel from it.
// This will create the file if it doesn't exit. We'll arrange
// for it to be deleted below, if we succeed in locking it.
file = new RandomAccessFile(lockfile, "rw");
f = file.getChannel();
// Try to get an exclusive lock on the file.
// This method will return a lock or null, but will not block.
// See also FileChannel.lock() for a blocking variant.
lock = f.tryLock();
if (lock != null) {
// We obtained the lock, so arrange to delete the file when
// we're done, and then write the approximate time at which
// we'll relinquish the lock into the file.
lockfile.deleteOnExit(); // Just a temporary file
// First, we need a buffer to hold the timestamp
ByteBuffer bytes = ByteBuffer.allocate(8); // a long is 8 bytes
// Put the time in the buffer and flip to prepare for writing
// Note that many Buffer methods can be "chained" like this.
bytes.putLong(System.currentTimeMillis() + 10000).flip();
f.write(bytes); // Write the buffer contents to the channel
f.force(false); // Force them out to the disk
}
else {
// We didn't get the lock, which means another instance is
// running. First, let the user know this.
System.out.println("Another instance is already running");
// Next, we attempt to read the file to figure out how much
// longer the other instance will be running. Since we don't
// have a lock, the read may fail or return inconsistent data.
try {
ByteBuffer bytes = ByteBuffer.allocate(8);
f.read(bytes); // Read 8 bytes from the file
bytes.flip(); // Flip buffer before extracting bytes
long exittime = bytes.getLong(); // Read bytes as a long
// Figure out how long that time is from now and round
// it to the nearest second.
long secs = (exittime-System.currentTimeMillis()+500)/1000;
// And tell the user about it.
System.out.println("Try again in about "+secs+" seconds");
}
catch(IOException e) {
// This probably means that locking is enforced by the OS
// and we were prevented from reading the file.
}
// This is an abnormal exit, so set an exit code.
System.exit(1);
}
// Simulate a real application by sleeping for 10 seconds.
System.out.println("Starting...");
Thread.sleep(10000);
System.out.println("Exiting.");
}
finally {
// Always release the lock and close the file
// Closing the RandomAccessFile also closes its FileChannel.
if (lock != null && lock.isValid()) lock.release();
if (file != null) file.close();
}