【教えてJavaのエロい人】java.nio.channels.FileLockで共有ロック出来ねぇんですけど

試しにこんなコード書いてみたんですけど、共有ロックの時にも排他ロックがかかってるようにしか見えないんすよね…。

内容としては、以下の処理を順にやってるつもり:

  • a.dat, b.datへ書き込むスレッドを4つづつ作って排他ロック、a.datだったら書込み後に3000msスリープ
  • a.dat, b.datを読み込むスレッドを4つづつ作って共有ロック、a.datだったら読み込み後に3000msスリープ

意図としては、後者はブロックせずに並行して全スレッドが走れるはず、と思ったんだけれど、どちらの場合もOverlappingFileLockExceptionになる。これでは排他ロックじゃないか。

ちなみに環境はLinuxMacでJDK6。環境が共有ロック非対応なの?それとも単に何か勘違いしている?

import java.nio.ByteBuffer;

public class Test1 {
	/**
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException {
		Test1 t1 = new Test1();
		t1.run();
	}

	private void run() throws InterruptedException {
		FileIOThread[] threads = new FileIOThread[8];
		System.out.println("write test");
		for (int i = 0; i < 8; i++) {
			ByteBuffer buf = ByteBuffer.allocate(10);
			buf.put("abc".getBytes());
			threads[i] = new FileIOThread(i < 4 ? "a.dat" : "b.dat", FileIOType.WRITE, buf);
			threads[i].start();
		}
		for (int i = 0; i < 8; i++) {
			threads[i].join();
		}
		System.out.println("read test");
		for (int i = 0; i < 8; i++) {
			ByteBuffer buf = ByteBuffer.allocate(10);
			threads[i] = new FileIOThread(i < 4 ? "a.dat" : "b.dat", FileIOType.READ, buf);
			threads[i].start();
		}
	}

}
public enum FileIOType {
	READ, WRITE
}
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;

public class FileIOThread extends Thread {
	private final String fileName;
	private final FileIOType type;
	private final ByteBuffer data;

	public FileIOThread(String fileName, FileIOType type, ByteBuffer data) {
		this.fileName = fileName;
		this.type = type;
		this.data = data;
	}

	@Override
	public void run() {
		File file = new File(fileName);
		FileLock lock = null;
		FileChannel channel = null;

		try {
			channel = new RandomAccessFile(file, type == FileIOType.READ ? "r" : "rw").getChannel();
			while (true) {
				try {
					lock = channel.tryLock(0L, Long.MAX_VALUE, type == FileIOType.READ);
					if (lock != null)
						break;
					else
						System.out.printf("%d:%d:%s blocked by null\n", System
								.currentTimeMillis(), Thread.currentThread().getId(),
								fileName);
				} catch (OverlappingFileLockException e) {
					System.out.printf("%d:%d:%s blocked by Exception\n", System
							.currentTimeMillis(), Thread.currentThread().getId(),
							fileName);
				}
				Thread.sleep(1000);
			}
			System.out.printf("%d:%d:%s isShared = %b\n", System
						.currentTimeMillis(), Thread.currentThread().getId(),
						fileName, lock.isShared());
			if (type == FileIOType.READ) {
				channel.read(data);
				System.out.printf("%d:%d:%s read success\n", System
						.currentTimeMillis(), Thread.currentThread().getId(),
						fileName);
			} else {
				channel.write(data);
				System.out.printf("%d:%d:%s write success\n", System
						.currentTimeMillis(), Thread.currentThread().getId(),
						fileName);
			}
			if (fileName.equals("a.dat"))
				Thread.sleep(3000);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				lock.release();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				channel.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}