概述
FileLock是java 1.4 版本后出現的一個類,它可以通過對一個可寫文件(w)加鎖,保證同時只有一個進程可以拿到文件的鎖,這個進程從而可以對文件做訪問;而其它拿不到鎖的進程要么選擇被掛起等待,要么選擇去做一些其它的事情, 這樣的機制保證了眾進程可以順序訪問該文件。也可以看出,能夠利用文件鎖的這種性質,在一些場景下,雖然我們不需要操作某個文件, 但也可以通過 FileLock 來進行并發控制,保證進程的順序執行,避免數據錯誤。
共享鎖、獨占鎖
- 共享鎖:允許多個線程進行文件的讀取操作
- 獨占鎖: 只允許一個線程進行文件的讀/寫操作
獲得 FileLock
通過 NIO 的 API 首先獲取文件的 FileChannel ,然后可以通過 FileChannel 以下4中方式獲取FileLock。
1. 通過lock() 獲取 FileLock,獲取文件的獨占鎖
public final FileLock lock() throws IOException {
return lock(0L, Long.MAX_VALUE, false);
}
默認鎖定整個文件,并設置為獨占鎖。
2. 通過改方法可以鎖定文件的部分數據,并支持設置共享鎖。
public FileLock lock(long position, long size, boolean shared) throws IOException{
......
}
- position:鎖定文件中的開始位置
- size: 鎖定文件中的內容長度
- shared: 是否使用共享鎖。true為共享鎖定;false為獨占鎖定。
一些不支持共享鎖的操作系統,將自動將共享鎖改成排它鎖。可以通過調用isShared()方法來檢測獲得的是什么類型的鎖。
3. 試圖獲取文件獨占鎖
public final FileLock tryLock() throws IOException {
return tryLock(0L, Long.MAX_VALUE, false);
}
如果獲取不到鎖,則返回null。而不阻塞當前線程,等待獲取鎖。
4. 通過改方法可以嘗試獲得文件的部分數據的鎖,并支持設置共享鎖。
public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException{
......
}
參數同上2。
如果獲取不到鎖,則返回null。
使用場景
- 如果多個應用部署到同一臺機器上,并且同時操作同一份數據(數據庫中或文件中的數據),可以使用FileLock充當分布式鎖。
示例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class FileLockTest {
public static void main(String[] args){
FileLock lock = null;
try (FileChannel channel = new FileOutputStream("d:\\file.lock",true).getChannel()){
lock = channel.lock();//無參lock()為獨占鎖
//lock = channel.lock(0L, channel.size(), true); //共享鎖
//其它邏輯
......
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (lock != null) {
try {
lock.release();
lock = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- 對于一個只讀文件通過任意方式加鎖時會報NonWritableChannelException異常
- 無參lock()默認為獨占鎖,不會報NonReadableChannelException異常,因為獨占就是為了寫
- 有參lock()為共享鎖,所謂的共享也只能讀共享,寫是獨占的,共享鎖控制的代碼只能是讀操作,當有寫沖突時會報NonWritableChannelException異常
想了解更多精彩內容請關注我的公眾號