如前面提到的,文件映射通常应用于极大的文件。因此我们可能需要对如此巨大的文件进行
部分加锁,以便其他进程可以修改文件中未被加锁的部分。例如,数据库就是这样,因此多
个用户可以同时访问到它。
下面例子中有两个线程,分别加锁文件的不同部分。
//: c12:LockingMappedFiles.java
// Locking portions of a mapped file.
// {RunByHand}
// {Clean: test.dat}
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class LockingMappedFiles {
static final int LENGTH = 0x8FFFFFF; // 128 Mb
static FileChannel fc;
public static void main(String[] args) throws Exception {
fc =
new RandomAccessFile("test.dat", "rw").getChannel();
MappedByteBuffer out =
fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
for(int i = 0; i < LENGTH; i++)
out.put((byte)'x');
new LockAndModify(out, 0, 0 + LENGTH/3);
new LockAndModify(out, LENGTH/2, LENGTH/2 + LENGTH/4);
}
private static class LockAndModify extends Thread {
private ByteBuffer buff;
private int start, end;
LockAndModify(ByteBuffer mbb, int start, int end) {
this.start = start;
this.end = end;
mbb.limit(end);
mbb.position(start);
buff = mbb.slice();
start();
}
public void run() {
try {
// Exclusive lock with no overlap:
FileLock fl = fc.lock(start, end, false);
System.out.println("Locked: "+ start +" to "+ end);
// Perform modification:
while(buff.position() < buff.limit() - 1)
buff.put((byte)(buff.get() + 1));
fl.release();
System.out.println("Released: "+start+" to "+ end);
} catch(IOException e) {
throw new RuntimeException(e);
}
}
}
} ///:~
线程类 LockAndModify 创建了缓冲区和用于修改的 slice( ),然后在 run()中,获得文
件通道上的锁(我们不能获得缓冲器上的锁——只能是通道上的)。lock()调用类似于在
一个工程上获得线程锁——我们现在处在“临界区”,即对该部分的文件具有独占访问权。
如果有 Java 虚拟机,它会自动释放锁,或者关闭加锁的通道。不过我们也可以像程序中那
部分加锁,以便其他进程可以修改文件中未被加锁的部分。例如,数据库就是这样,因此多
个用户可以同时访问到它。
下面例子中有两个线程,分别加锁文件的不同部分。
//: c12:LockingMappedFiles.java
// Locking portions of a mapped file.
// {RunByHand}
// {Clean: test.dat}
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class LockingMappedFiles {
static final int LENGTH = 0x8FFFFFF; // 128 Mb
static FileChannel fc;
public static void main(String[] args) throws Exception {
fc =
new RandomAccessFile("test.dat", "rw").getChannel();
MappedByteBuffer out =
fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
for(int i = 0; i < LENGTH; i++)
out.put((byte)'x');
new LockAndModify(out, 0, 0 + LENGTH/3);
new LockAndModify(out, LENGTH/2, LENGTH/2 + LENGTH/4);
}
private static class LockAndModify extends Thread {
private ByteBuffer buff;
private int start, end;
LockAndModify(ByteBuffer mbb, int start, int end) {
this.start = start;
this.end = end;
mbb.limit(end);
mbb.position(start);
buff = mbb.slice();
start();
}
public void run() {
try {
// Exclusive lock with no overlap:
FileLock fl = fc.lock(start, end, false);
System.out.println("Locked: "+ start +" to "+ end);
// Perform modification:
while(buff.position() < buff.limit() - 1)
buff.put((byte)(buff.get() + 1));
fl.release();
System.out.println("Released: "+start+" to "+ end);
} catch(IOException e) {
throw new RuntimeException(e);
}
}
}
} ///:~
线程类 LockAndModify 创建了缓冲区和用于修改的 slice( ),然后在 run()中,获得文
件通道上的锁(我们不能获得缓冲器上的锁——只能是通道上的)。lock()调用类似于在
一个工程上获得线程锁——我们现在处在“临界区”,即对该部分的文件具有独占访问权。
如果有 Java 虚拟机,它会自动释放锁,或者关闭加锁的通道。不过我们也可以像程序中那
样,显式地为 FileLock 调用 release()释放锁。