FileLock的疑惑和一些理解

最近碰到一個項目,有多個進程,同時操作同一目錄的同一文件,筆者使用java語言。由於文件比較小,所以上線後並沒有碰到什麼問題。但是,我不禁想到一些問題:不同進程對同一個文件進行操作,如何保證數據的正確性。

如果在同一進程之內,我完全可以在寫文件的時候,加一把對象鎖,同一時刻,只能有一個線程寫文件。but,我的問題是不同進程之間如何保證。

於是,我找到一個東西FileLock,關於FileLock我做了一些測試,最終也並沒有達到我要的效果。希望牛人們能提供點思路,幫我解惑。

我寫了一個測試類,分兩次給文件寫入1111111和222222,在寫之前獲取一把文件鎖,程序結束,在finally關閉掉鎖。

	public static void main(String[] args) {
		FileOutputStream fos = null;
		FileLock fLock = null;
		try {
			System.out.println("starting...");
			fos = new FileOutputStream(PATH);
			fLock = fos.getChannel().lock();
			fos.write("1111111".getBytes());
			fos.flush();
			fos.write("2222222".getBytes());//此處加了一個斷點
			fos.flush();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fLock != null)
				try {
					fLock.release();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (fos != null)
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}

注意,以上代碼標註的地方,我加了一個斷點。然後我發現,用windows自帶的文本編輯工具,當改變文件內容的時候會報錯:

到這裏來看,似乎都沒有什麼問題。

現在,我用nodepad++打開這個文件,首先,內容已經沒有了(我想大概是因爲沒有獲取到文件鎖,所以無法讀取內容吧)

but,讓我無法理解的地方來了,我在裏面寫入內容,然後保存,nodepad沒有報任何異常(我想,大概是因爲他自己捕捉了異常吧)

然後,我再用windows自帶的文本工具打開,看到的內容是一片空白!!!!!!(到這裏我已經無法理解了)

然後,有回到eclipse工程,在剛剛斷點的地方,我直接讓程序跑完,程序沒有報出任何異常,在用windows自帶的工具打開,看到內容如下:


到這裏來看,似乎都沒有什麼問題。

現在,我用nodepad++打開這個文件,首先,內容已經沒有了(我想大概是因爲沒有獲取到文件鎖,所以無法讀取內容吧)



but,讓我無法理解的地方來了,我在裏面寫入內容,然後保存,nodepad沒有報任何異常(我想,大概是因爲他自己捕捉了異常吧)

然後,我再用windows自帶的文本工具打開,看到的內容是一片空白!!!!!!(到這裏我已經無法理解了)



然後,有回到eclipse工程,在剛剛斷點的地方,我直接讓程序跑完,程序沒有報出任何異常,在用windows自帶的工具打開,看到內容如下:


從這個結果可以看出,之前寫入1111111的地方,被"髒寫"了。

所以,我想在不同進程之間,對文件的寫操作進行保護,看來是失敗了。

之後,我又做了幾個嘗試:

1.同樣兩個程序,都是用java跑的,是兩個進程,第一個程序就是上面的代碼裏的,也同樣,在上面斷點;第二個程序就是直接寫文件。神奇的事情又發生了,第二程序確實會拋出異常,說另一個程序正在使用,but,文件裏面的內容也是被“髒寫”了。最後釋放斷點,最後得到的結果跟上面一樣。

2.兩個程序,第一個用java寫,更上面一樣,第二程序用c++寫,調試方法和上面一樣,得到相同的實驗結果。

那麼我考慮,java這個FileLock是否是對文件的內存映射進行加鎖,想了下,不對,因爲如果是這樣,那麼這個鎖僅僅在本個java進程有效;

如果是直接鎖文件呢?想了下,也不太可能,windows上似乎並沒有這種機制;

再來,我請教一個大牛,大牛說,windows對於文件的操作,是有一個文件映射的句柄,或者說文件句柄,所有的操作都是對這個句柄進行操作的,好吧,我也很疑惑。

所以,綜上所述,就是沒有解決我的問題,各位大神有啥解決思路沒有?

------------------------------------------------------------------------------------------------------------------------------------------------------

先假設上面的問題不存在,FileLock是一個很完美的鎖禁止,並且以下的嘗試都用java語言,以下是我對FileLock的一些理解:

另外,在使用FileLock的時候,有一個lock(int start,int size,boolean isShare)的方法,帶參數的喲。關於這個start和size就感覺非常奇怪,這個又是鎖的啥,難道文件還是鎖指定範圍?答案是否定的。

首先說,FileLock有兩種鎖:

排他鎖:只有當前線程可以讀寫,其他的線程或者進程對這個進行讀或者寫都會拋出異常

共享鎖:當前線程可以操作,但是,要用RandomAccessFile並且要"rw",否則會拋異常,不信,你可以試試. 其他線程或者進程,可以讀取。在鎖住的時候,寫,只能自己寫,別人只能讀

然後來說這個start和size,這個,似乎又是鎖的channel,只對同一進程有效:

lock = channel.lock(0, 4, true);
lock = channel.lock(4, 8, true);

然後,這樣是ok的

lock = channel.lock(0, 4, true);
lock = channel.lock(3, 8, true);

但是這樣就不ok了。然後api裏面提供了一個overlaps的方法,我做了一些實驗,也沒發現有啥效果。

再有就是,我同樣的程序獲得鎖的地方加了一個斷點,然後做最開始的那些測試,實驗結果一樣,不好。

然後神奇的事情又發發生了,我用下面的代碼:

FileOutputStream fos = null;
FileLock fLock = null;
try {
	System.out.println("starting...");
	fos = new FileOutputStream(PATH);
	fLock = fos.getChannel().lock();
	fos.write("1111111".getBytes());
	fos.flush();
	fos.write("2222222".getBytes());
	fos.flush();
}..........

確實,會在獲取lock的地方,阻塞,等待鎖。

but,我再用這段代碼:

FileLock lock = null;
FileChannel channel = null;
try {
	RandomAccessFile raf = new RandomAccessFile(new File(FileLocking.PATH),"rw");
	raf.seek(4);
	channel = raf.getChannel();
	lock = channel.lock(0, 4, true);
	System.out.println("2222");
}........

卻發現,程序完全的執行了,並不會再加粗的地方獲取等待。

好吧,繼續一萬點的暴擊傷害。

-------------------------------------------------------------------------------------------------------------------

綜上所述,我覺得,應該是我錯誤的使用了FileLock,請各位大牛指點批評。最主要的疑惑點在於:

1.不同進程之間,如果使用文件鎖;

2.FileLock帶參數的lock如何正確的使用,以及參數的含義

3.FileLock的lock到底鎖的是什麼對象,是否帶參數的lock和不帶參數的lock鎖的是不同的對象

基於上面碰到的問題,如果真的要我使用文件鎖的話,我會這麼做:

1.在寫文件的時候,儘量使用排他鎖,也就是直接使用不帶參數的lock或者tryLock,這是讀文件的時候,如果有異常應該捕獲,下次重讀。那麼也要求,寫文件不能太頻繁。

2.多個進程操作文件的時候,儘量不要操作同一個文件,否則有些不可預見的錯誤(是我自己知識面不夠吧)


























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章