JAVA NIO 文件鎖FileLock

文件鎖可以是shared(共享鎖)或者exclusive(排他鎖)。不是所有的平臺都以同一種方式實(shí)現(xiàn)文件鎖姻几,不同的操作系統(tǒng)可能不同掸驱,同一操作系統(tǒng)上的不同文件系統(tǒng)也可能不同。有些操作系統(tǒng)只提供協(xié)同鎖饭豹,有些只提供強(qiáng)制鎖鸵赖,有些則都提供。

文件鎖是以文件為單位的拄衰,不是以通道它褪,也不是線程。所以文件鎖不適合同一個(gè)多個(gè)線程訪問的情形翘悉。如果一個(gè)線程獲得了給定文件的排他鎖茫打,第二個(gè)線程請求打開了一個(gè)新的channel,請求獲得排他鎖镐确,請求會被批準(zhǔn)包吝。但如果這兩個(gè)線程運(yùn)行在不同的JVM中,第二個(gè)線程會阻塞源葫,因?yàn)殒i往往是根據(jù)進(jìn)程來進(jìn)行裁決诗越,而不是線程。鎖工作于一個(gè)文件息堂,而不是單獨(dú)的文件處理器或是通道嚷狞。
/*
如果你需要控制多個(gè)線程之間的同步,你可能需要實(shí)現(xiàn)自己的輕量級的鎖荣堰,內(nèi)存映射文件可能是個(gè)適合的選擇
*/

public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
  
  public final FileLock lock()
  public abstract FileLock lock (long position, long size, boolean shared)

  public final FileLock tryLock()
  public abstract FileLock tryLock(long position, long size, boolean shared)
}

先看帶參數(shù)的lock方法床未,獲得給定區(qū)域的鎖,自position開始振坚,size大小薇搁,第三個(gè)布爾參數(shù)代表是鎖是否共享。鎖的區(qū)域并不受到文件大小的限制渡八,鎖可以超過文件的大小啃洋,也就是說在一段區(qū)域被寫入數(shù)據(jù)之前鎖住,是可行的屎鳍。相反的宏娄,如果文件的大小超出了鎖的限制,也就將不受到鎖的限制逮壁。不帶參數(shù)的lock方法孵坚,等效于
fileChannel.lock(0L,Long.MAX_VALUE, false);
如果你的請求是有效的,那么lock方法就會生效,但是要等待前一個(gè)鎖(如果存在的話)釋放卖宠。

tryLock方法是lock方法非阻塞的變種巍杈,功能和lock相似,但是如果不能立刻獲得鎖的話逗堵,tryLock會返回null秉氧。從創(chuàng)建開始,直到調(diào)用FileLock的release方法蜒秤,F(xiàn)ileLock對象都是有效的汁咏。可以通過isValid方法測試作媚。一個(gè)鎖是否有效可能會改變攘滩,但鎖的位置,大小纸泡,是否共享漂问,是不變的。

你可以通過isShared判斷鎖是否為共享鎖女揭,如果內(nèi)在的文件系統(tǒng)操作系統(tǒng)不支持共享蚤假,那么這個(gè)方法總是會返回false,就算你傳遞true作為構(gòu)造函數(shù)也一樣吧兔。FileLock是線程安全的磷仰,多個(gè)線程可以通過一個(gè)FileLock進(jìn)行操作。盡管FileLock對象和一個(gè)Channel相關(guān)境蔼,但是其實(shí)鎖是和內(nèi)在的文件聯(lián)系的灶平。這有可能造成沖突,也有可能死鎖箍土,如果你完成了操作而沒有釋放鎖的話逢享。一個(gè)典型的代碼如下所示:

FileLock lock = fileChannel.lock();
try{
  <perform read/write/whatever on channel>
} catch (IOException e) {
  <handle unexcepted exception>
} finally {
  lock.release();
}

下面是一個(gè)使用FileLock進(jìn)行操作的例子


    private static final int SIZEOF_INT = 4;
    private static final int INDEX_START = 0;
    private static final int INDEX_COUNT = 10;
    private static final int INDEX_SIZE = INDEX_COUNT * SIZEOF_INT;

    private ByteBuffer buffer = ByteBuffer.allocate(INDEX_SIZE);
    private IntBuffer indexBuffer = buffer.asIntBuffer();
    private Random rand = new Random();

    public static void main(String[] args) throws Exception{
        boolean writer = false;
        String filename;
        //決定你所做的操作,讀或者寫
        if(args.length!=2) {
            System.out.println("Usage: [-r|-w] filename");
            return;
        }
        writer = args[0].equals("-w");//true寫false讀
        filename = args[1];
        RandomAccessFile raf = new RandomAccessFile(filename,writer?"rw":"r");
        FileChannel fc = raf.getChannel();//通過RandomAccessFile拿到fileChannel
        LockTest lockTest = new LockTest();
        if(writer) {
            lockTest.doUpdates(fc);
        } else {
            lockTest.doQueries(fc);
        }
    }

    void doQueries (FileChannel fc) throws Exception {
        //如果是單次操作的話吴藻,沒有這個(gè)循環(huán)瞒爬,這里使用這個(gè)循環(huán),為了多次
        //運(yùn)行程序沟堡,發(fā)現(xiàn)鎖的工作原理
        while (true) {
            FileLock lock = fc.lock(INDEX_START,INDEX_SIZE,true);
            int reps = rand.nextInt(60) + 20;
            for(int i=0; i<reps; i++) {
                int n = rand.nextInt(INDEX_COUNT);
                int position = INDEX_START + (n*SIZEOF_INT);
                buffer.clear();
                fc.read(buffer,position);
                int value = indexBuffer.get(n);
                Thread.sleep(100);//doing some work
            }
            lock.release();
            Thread.sleep(rand.nextInt(3000)+500);
        }
    }

    void doUpdates (FileChannel fc) throws Exception {
        while (true) {
            FileLock lock = fc.lock(INDEX_START,INDEX_SIZE,false);
            updateIndex(fc);
            lock.release();
            Thread.sleep(rand.nextInt(2000)+500);
        }
    }

    private int idxval = 1;

    private void updateIndex (FileChannel fc) throws Exception{
        indexBuffer.clear();
        for(int i=0; i<INDEX_COUNT; i++) {
            idxval++;
            indexBuffer.put(idxval);
            Thread.sleep(500);
        }
        buffer.clear();
        fc.write(buffer,INDEX_START);
    }


}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疮鲫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弦叶,更是在濱河造成了極大的恐慌,老刑警劉巖妇多,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伤哺,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)立莉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門绢彤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜓耻,你說我怎么就攤上這事茫舶。” “怎么了刹淌?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵饶氏,是天一觀的道長。 經(jīng)常有香客問我有勾,道長疹启,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任蔼卡,我火速辦了婚禮喊崖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雇逞。我一直安慰自己荤懂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布塘砸。 她就那樣靜靜地躺著节仿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谣蠢。 梳的紋絲不亂的頭發(fā)上粟耻,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音眉踱,去河邊找鬼挤忙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谈喳,可吹牛的內(nèi)容都是我干的册烈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼婿禽,長吁一口氣:“原來是場噩夢啊……” “哼赏僧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扭倾,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤淀零,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膛壹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驾中,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唉堪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肩民。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唠亚。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖持痰,靈堂內(nèi)的尸體忽然破棺而出灶搜,到底是詐尸還是另有隱情,我是刑警寧澤工窍,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布割卖,位于F島的核電站,受9級特大地震影響移剪,放射性物質(zhì)發(fā)生泄漏究珊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一纵苛、第九天 我趴在偏房一處隱蔽的房頂上張望剿涮。 院中可真熱鬧,春花似錦攻人、人聲如沸取试。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞬浓。三九已至,卻和暖如春蓬坡,著一層夾襖步出監(jiān)牢的瞬間猿棉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工屑咳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萨赁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓兆龙,卻偏偏與公主長得像杖爽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子紫皇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容