系統中不同Java進程通常情況下運行於不同的Java虛擬機資源中(JVM),擁有獨立的數據和邏輯空間,彼此秋毫無犯,並不會產生相互干擾。但 一些特殊的情況下,兩個Java的進程間會對同時訪問系統中相同的數據、或者同時操作相同的資源,容易產生並發錯誤。更多的關於進程和並發的內容,請參考這里。
機會主義者總是覺得這個概率太小了,自己運氣好,在自己退休之前這個潛在的bug不會爆發。不過相信我,巧合和意外總是會更輕易的發生的,尤其是業務大副增長的前提下。所以為了避免不必要的損失和批評甚至扣薪,我們要對訪問同一資源的不同Java程序做並發控制。
FileLock是java 1.4 版本后出現的一個類,它可以通過對一個可寫文件(w)加鎖,保證同時只有一個進程可以拿到文件的鎖,這個進程從而可以對文件做訪問;而其它拿不到鎖的進程 要么選擇被掛起等待,要么選擇去做一些其它的事情,這樣的機制保證了眾進程可以順序訪問該文件。也可以看出,能夠利用文件鎖的這種性質,在一些場景下,雖 然我們不需要操作某個文件,但也可以通過 FileLock 來進行並發控制,保證進程的順序執行,避免數據錯誤。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package
com.ngloom.lock;
import
java.io.File;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.nio.channels.FileChannel;
import
java.nio.channels.FileLock;
import
java.util.Date;
public
class
Lock1 {
public
static
void
main(String[] args){
//文件鎖所在文件
File lockFile =
new
File(
"tmp"
);
FileOutputStream outStream =
null
;
FileLock lock =
null
;
try
{
outStream =
new
FileOutputStream(lockFile);
FileChannel channel = outStream.getChannel();
try
{
//方法一
lock = channel.lock();
System.out.println(
"Get the Lock!"
);
//do something...
//方法二
//lock = channel.tryLock();
//if(lock != null){
// do something..
//}
}
catch
(IOException e) {
e.printStackTrace();
}
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
finally
{
if
(
null
!= lock){
try
{
System.out.println(
"Release The Lock"
+
new
Date().toString());
lock.release();
}
catch
(IOException e) {
e.printStackTrace();
}
}
if
(outStream !=
null
){
try
{
outStream.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
}
}
|
如代碼所示,需要進行互斥的進程只要將自己的代碼替換掉//do something處即可,每個進程在運行實際邏輯功能代碼之前,會嘗試獲取鎖文件鎖,得到文件鎖的進程可以繼續執行后續的代碼,而沒有獲得鎖文件的進程 將被操作系統掛起(suspend),等到其它進程將文件鎖釋放后再重新開始嘗試獲取文件鎖。
這樣子,進程就可以通過FileLock來實現間的互斥運行。
最后,關於Java的FileLock還需要再補充幾點,詳細的地文檔請看這里:
0.可以通過lock方法來獲取文件鎖,可以通過tryLock方來測試該文件鎖是否可用。二者的區別是那:lock()方法是阻塞的方法,當文件鎖不可用時,當前進程會被掛起;tryLock是非阻塞的方法,當文件鎖不可用時,tryLock()會得到null值。
1.同一進程內,在文件鎖沒有被釋放之前,不可以再次獲取。即在release()方法調用前,只能lock()或者tryLock()一次。
2. 進程鎖對於同一進程來說是共享(shared)的,即這個進程中的線程都可以操作這個文件鎖(且線程安全);對於不同的進程來說是互斥(exclusive)的,因為FileLock保證只能有一個進程通過lock()或者tryLock()方法獲得文件鎖。
3. 文件鎖的效果是與操作系統相關的。一些系統中文件鎖是強制性的(mandatory),就當Java的某進程獲得文件鎖后,操作系統將保證其它進程無法對 文件做操作了。而另一些操作系統的文件鎖是詢問式的(advisory),意思是說要想擁有進程互斥的效果,其它的進程也必須也按照API所規定的那樣來 申請或者檢測文件鎖,不然,將起不到進程互斥的功能。所以,文檔里建議將所有系統都當做是詢問式系統來處理,這樣程序更加安全也更容易移植。
