文件鎖 FileLock
Jdk 1.4 引入文件加鎖機制,它允許我們同步訪問某個作爲共享資源的文件。不過,競爭同一個文件的兩個線程可能在不同的JVM上;或者一個未java線程,另一個爲操作系統中其他的每個本地線程。文件鎖對其它的操作系統進程是可見的因爲java的文件鎖是直接映射到了本地操作系統的加鎖工具。
tryLcok和lock
tryLock()是非阻塞式的,它設法獲取鎖,但是如果不能獲得(但其他一些進程已經持有相同的鎖,並且不共享時),它將直接從方法調用返回。
Lock()則是阻塞式的,它將阻塞線程直至鎖可以獲得,或調用lock的線程中斷,或調用lock的通道關閉。使用release()方法可以釋放鎖。
對文件的一部分內容上鎖
可以使用如下的方法對文件的一部分內容上鎖:
lock(long position,long size,boolean shared);
tryLock(long position,long size,boolean shared)
其中,加鎖的區域由position-size決定,第三個參數指定是否使用共享鎖。
儘管無參數的加鎖方法根據文件尺寸的變化而變化,但是具有固定尺寸的鎖不隨文件尺寸的變化而變化,如果你獲得position到position+size部分的鎖,當文件增大,超出position+size時,那麼position+size之外的部分不會被鎖定。無參數的加鎖方法會對整個文件進行加鎖,甚至文件變大後也是如此。
獨佔鎖和共享鎖的使用需要底層操作系統支持,如果操作系統不支持共享鎖併爲每一個請求都創建一個鎖,那麼它就會使用獨佔鎖。可以通過FileLock.isShared()進行查詢。
例:鎖住文件並修改內容
配合MappedByteBuffer對文件的不同部分加鎖並用多個線程修改文件內容。
private static FileChannel channel;
public static void main(String[] args) throws IOException {
final int LENGTH = 1 << 10; // 1k
channel = new RandomAccessFile(to, "rw").getChannel();
// 映射文件 0 - 1kb 部分
MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
for (int i = 0; i < LENGTH; i++) {
mb.put((byte) 'A');
}
// 鎖住並修改文件的 0 - 1/3 部分
new LockAndModify(mb, 0, LENGTH / 3);
// 鎖住並修改文件的 1/2 - 3/4 部分
new LockAndModify(mb, LENGTH / 2, LENGTH / 2 + LENGTH / 4);
}
private static class LockAndModify extends Thread {
private ByteBuffer buffer;
private int start, end;
LockAndModify(ByteBuffer buffer, int start, int end) {
this.buffer = buffer;
this.start = start;
this.end = end;
buffer.limit(end);
buffer.position(start);
// 基於已有buffer創建新的buffer
this.buffer = buffer.slice();
start();
}
@Override
public void run() {
try {
// 阻塞鎖
FileLock lock = channel.lock(start, end, false);
P.out("locked: " + start + " " + end);
while (buffer.position() < buffer.limit() - 1) {
// 將大寫字母 A 變換爲小寫的 a
byte b = (byte) (buffer.get() + 32);
buffer.put(b);
}
lock.release();
P.out("release: " + start + " " + end);
} catch (IOException e) {
e.printStackTrace();
}
}
}
修改的文件:
輸出:
17/01/2018 14:39:38-320 locked: 512 768
17/01/2018 14:39:38-320 locked: 0 341
17/01/2018 14:39:38-321 release: 0 341
17/01/2018 14:39:38-321 release: 512 768
如果有JVM,文件鎖會被自動釋放,或者關閉加鎖的通道。不過更應該主動顯示的爲FileLock對象調用release方法釋放鎖。
文章大部分內容摘抄自《Thinking in java》第18章:18.10 新I/O