package com.ronsoft.books.nio.channels; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.io.RandomAccessFile; import java.util.Random; /** * Test locking with FileChannel. * Run one copy of this code with arguments "-w /tmp/locktest.dat" * and one or more copies with "-r /tmp/locktest.dat" to see the * interactions of exclusive and shared locks. Note how too many * readers can starve out the writer. * Note: The filename you provide will be overwritten. Substitute * an appropriate temp filename for your favorite operating system. * * Created April, 2002 * @author Ron Hitchens (ron@ronsoft.com) * @version $Id: LockTest.java,v 1.2 2002/05/19 04:55:45 ron Exp $ */ public class LockTest { private static final int SIZEOF_INT = 4; private static final int INDEX_START = 0; private static final int INDEX_COUNT = 10; private static final int INDEX_SIZE = INDEX_COUNT * SIZEOF_INT; private ByteBuffer buffer = ByteBuffer.allocate (INDEX_SIZE); private IntBuffer indexBuffer = buffer.asIntBuffer(); private Random rand = new Random(); public static void main (String [] argv) throws Exception { boolean writer = false; String filename; if (argv.length != 2) { System.out.println ("Usage: [ -r | -w ] filename"); return; } writer = argv [0].equals ("-w"); filename = argv [1]; RandomAccessFile raf = new RandomAccessFile (filename, (writer) ? "rw" : "r"); FileChannel fc = raf.getChannel(); LockTest lockTest = new LockTest(); if (writer) { lockTest.doUpdates (fc); } else { lockTest.doQueries (fc); } } // ---------------------------------------------------------------- // Simulate a series of read-only queries while // holding a shared lock on the index area void doQueries (FileChannel fc) throws Exception { while (true) { println ("trying for shared lock..."); FileLock lock = fc.lock (INDEX_START, INDEX_SIZE, true); int reps = rand.nextInt (60) + 20; for (int i = 0; i < reps; i++) { int n = rand.nextInt (INDEX_COUNT); int position = INDEX_START + (n * SIZEOF_INT); buffer.clear(); fc.read (buffer, position); int value = indexBuffer.get (n); println ("Index entry " + n + "=" + value); // Pretend to be doing some work Thread.sleep (100); } lock.release(); println (""); Thread.sleep (rand.nextInt (3000) + 500); } } // Simulate a series of updates to the index area // while holding an exclusive lock void doUpdates (FileChannel fc) throws Exception { while (true) { println ("trying for exclusive lock..."); FileLock lock = fc.lock (INDEX_START, INDEX_SIZE, false); updateIndex (fc); lock.release(); println (""); Thread.sleep (rand.nextInt (2000) + 500); } } // write new values to the index slots private int idxval = 1; private void updateIndex (FileChannel fc) throws Exception { // "indexBuffer" is an int view of "buffer" indexBuffer.clear(); for (int i = 0; i < INDEX_COUNT; i++) { idxval++; println ("Updating index " + i + "=" + idxval); indexBuffer.put (idxval); // Pretend to this is really hard work Thread.sleep (500); } // leaves position and limit correct for whole buffer buffer.clear(); fc.write (buffer, INDEX_START); } // ---------------------------------------------------------------- private int lastLineLen = 0; // Specialized println which repaints the current line private void println (String msg) { System.out.print ("\r "); System.out.print (msg); for (int i = msg.length(); i < lastLineLen; i++) { System.out.print (" "); } System.out.print ("\r"); System.out.flush(); lastLineLen = msg.length(); } }