Java 文件鎖 FileLock 在多線程中的解析

問:下面程序能正常運行嗎?分析一下你的看法?
public class Test {
    private static void thread1() {
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");
            FileChannel channel = randomAccessFile.getChannel();

            FileLock lock = channel.lock();
            System.out.println("write get lock.");

            for (int i = 0; i < 5; i++) {
                String content = "{"+i+"}"+new Date()+"\n";
                randomAccessFile.writeChars(content);
                System.out.println("write content:" + content);
                Thread.sleep(1000);
            }
            lock.release();
            System.out.println("write release lock.");

            randomAccessFile.close();
            channel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void thread2() {
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");
            FileChannel channel = randomAccessFile.getChannel();
            Thread.sleep(2000);

            FileLock lock = null;
            do {
                lock = channel.tryLock();
            } while (null == lock);
            System.out.println("read get lock.");

            System.out.println("read get content lines:" + randomAccessFile.length());

            lock.release();
            System.out.println("read release lock.");

            randomAccessFile.close();
            channel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread("T1") {
            @Override
            public void run() {
                thread1();
            }
        }.start();

        new Thread("T2") {
            @Override
            public void run() {
                thread2();
            }
        }.start();
    }
}

答:可以運行,只是得不到程序想要的效果,因為上面程序的運行結(jié)果會是類似如下輸出:

write get lock.
write content:{0}Fri Aug 10 10:14:49 CST 2018
write content:{1}Fri Aug 10 10:14:50 CST 2018
//thread2()方法的 tryLock 拋出異常
java.nio.channels.OverlappingFileLockException
    at sun.nio.ch.SharedFileLockTable.checkList(FileLockTable.java:255)
    at sun.nio.ch.SharedFileLockTable.add(FileLockTable.java:152)
    at sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:1108)
    at java.nio.channels.FileChannel.tryLock(FileChannel.java:1155)
    at Test.thread2(Test.java:39)
    at Test.access$100(Test.java:6)
    at Test$2.run(Test.java:66)

write content:{2}Fri Aug 10 10:14:51 CST 2018
write content:{3}Fri Aug 10 10:14:52 CST 2018
write content:{4}Fri Aug 10 10:14:53 CST 2018
write release lock.

首先上面例子中 lock() 和 tryLock() 的區(qū)別如下:

  • lock() 為阻塞方法,鎖定范圍可以隨著文件的增大而增加,無參 lock() 默認為獨占鎖,有參 lock(0L, Long.MAX_VALUE, true) 為共享鎖。

  • tryLock() 為非阻塞方法,當(dāng)未獲得鎖時返回 null,無參 tryLock() 默認為獨占鎖,有參 tryLock(0L, Long.MAX_VALUE, true) 為共享鎖。

此外 FileLock 的生命周期在調(diào)用 FileLock.release() 或者 Channel.close() 或者 JVM 關(guān)閉時才會結(jié)束。

而我們上面程序之所以會拋出異常是因為在同一進程內(nèi),文件鎖 FileLock 沒有被釋放之前不可以再次獲?。丛?release() 方法調(diào)用前只能 lock() 或 tryLock() 一次),因為文件鎖 FileLock 的效果是與操作系統(tǒng)相關(guān)的,所以上面程序會拋出文件重疊鎖異常。

要想讓上面程序在多線程及多進程中同時可用,則最簡單的修改思路可以參考把 lock-release 部分再用 Java 線程鎖(譬如 synchronized)進行包起來即可。當(dāng)然這只是建議,具體還是要取決于業(yè)務(wù)多線程及進程同步并發(fā)場景的需求進行設(shè)計改良。

本文參考自 文件鎖 FileLock 在多線程中的挖坑題解析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容