Java進程互斥–FileLock


系統中不同Java進程通常情況下運行於不同的Java虛擬機資源中(JVM),擁有獨立的數據和邏輯空間,彼此秋毫無犯,並不會產生相互干擾。但 一些特殊的情況下,兩個Java的進程間會對同時訪問系統中相同的數據、或者同時操作相同的資源,容易產生並發錯誤。更多的關於進程和並發的內容,請參考這里

機會主義者總是覺得這個概率太小了,自己運氣好,在自己退休之前這個潛在的bug不會爆發。不過相信我,巧合和意外總是會更輕易的發生的,尤其是業務大副增長的前提下。所以為了避免不必要的損失和批評甚至扣薪,我們要對訪問同一資源的不同Java程序做並發控制。

FileLock是java 1.4 版本后出現的一個類,它可以通過對一個可寫文件(w)加鎖,保證同時只有一個進程可以拿到文件的鎖,這個進程從而可以對文件做訪問;而其它拿不到鎖的進程 要么選擇被掛起等待,要么選擇去做一些其它的事情,這樣的機制保證了眾進程可以順序訪問該文件。也可以看出,能夠利用文件鎖的這種性質,在一些場景下,雖 然我們不需要操作某個文件,但也可以通過 FileLock 來進行並發控制,保證進程的順序執行,避免數據錯誤。

Lock.java
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所規定的那樣來 申請或者檢測文件鎖,不然,將起不到進程互斥的功能。所以,文檔里建議將所有系統都當做是詢問式系統來處理,這樣程序更加安全也更容易移植。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM