java nio - 2 文件加鎖

文件鎖 FileLock

Jdk 1.4 引入文件加鎖機制,它允許我們同步訪問某個作爲共享資源的文件。不過,競爭同一個文件的兩個線程可能在不同的JVM上;或者一個未java線程,另一個爲操作系統中其他的每個本地線程。文件鎖對其它的操作系統進程是可見的因爲java的文件鎖是直接映射到了本地操作系統的加鎖工具。

這裏寫圖片描述

tryLcok和lock

tryLock()是非阻塞式的,它設法獲取鎖,但是如果不能獲得(但其他一些進程已經持有相同的鎖,並且不共享時),它將直接從方法調用返回。

Lock()則是阻塞式的,它將阻塞線程直至鎖可以獲得,或調用lock的線程中斷,或調用lock的通道關閉。使用release()方法可以釋放鎖。

對文件的一部分內容上鎖

可以使用如下的方法對文件的一部分內容上鎖:
lock(long position,long size,boolean shared);
tryLock(long position,long size,boolean shared)
其中,加鎖的區域由position-size決定,第三個參數指定是否使用共享鎖。

儘管無參數的加鎖方法根據文件尺寸的變化而變化,但是具有固定尺寸的鎖不隨文件尺寸的變化而變化,如果你獲得position到position+size部分的鎖,當文件增大,超出position+size時,那麼position+size之外的部分不會被鎖定。無參數的加鎖方法會對整個文件進行加鎖,甚至文件變大後也是如此。

獨佔鎖和共享鎖的使用需要底層操作系統支持,如果操作系統不支持共享鎖併爲每一個請求都創建一個鎖,那麼它就會使用獨佔鎖。可以通過FileLock.isShared()進行查詢。

例:鎖住文件並修改內容

配合MappedByteBuffer對文件的不同部分加鎖並用多個線程修改文件內容。


    private static FileChannel channel;

    public static void main(String[] args) throws IOException {
        final int LENGTH = 1 << 10; // 1k
        channel = new RandomAccessFile(to, "rw").getChannel();

        // 映射文件 0 - 1kb 部分
        MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
        for (int i = 0; i < LENGTH; i++) {
            mb.put((byte) 'A');
        }
        // 鎖住並修改文件的 0 - 1/3 部分
        new LockAndModify(mb, 0, LENGTH / 3);

        // 鎖住並修改文件的 1/2 - 3/4 部分
        new LockAndModify(mb, LENGTH / 2, LENGTH / 2 + LENGTH / 4);
    }

    private static class LockAndModify extends Thread {
        private ByteBuffer buffer;
        private int start, end;

        LockAndModify(ByteBuffer buffer, int start, int end) {
            this.buffer = buffer;
            this.start = start;
            this.end = end;
            buffer.limit(end);
            buffer.position(start);

            // 基於已有buffer創建新的buffer
            this.buffer = buffer.slice();
            start();
        }

        @Override
        public void run() {
            try {

                // 阻塞鎖
                FileLock lock = channel.lock(start, end, false);
                P.out("locked: " + start + " " + end);
                while (buffer.position() < buffer.limit() - 1) {
                    // 將大寫字母 A 變換爲小寫的 a
                    byte b = (byte) (buffer.get() + 32);
                    buffer.put(b);
                }
                lock.release();
                P.out("release: " + start + " " + end);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

修改的文件:
這裏寫圖片描述

輸出:
17/01/2018 14:39:38-320 locked: 512 768
17/01/2018 14:39:38-320 locked: 0 341
17/01/2018 14:39:38-321 release: 0 341
17/01/2018 14:39:38-321 release: 512 768

如果有JVM,文件鎖會被自動釋放,或者關閉加鎖的通道。不過更應該主動顯示的爲FileLock對象調用release方法釋放鎖。


文章大部分內容摘抄自《Thinking in java》第18章:18.10 新I/O

—END—

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