溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中怎么鎖文件

發(fā)布時(shí)間:2021-06-21 14:27:10 來源:億速云 閱讀:108 作者:chen 欄目:編程語言

本篇內(nèi)容主要講解“Java中怎么鎖文件”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java中怎么鎖文件”吧!

1. 概覽

當(dāng)讀寫文件時(shí),需要確保有適當(dāng)?shù)奈募i定機(jī)制,來保證基于并發(fā)I/O應(yīng)用程序的數(shù)據(jù)完整性。

「本教程中, 我們將介紹使用 Java NIO 庫實(shí)現(xiàn)這一點(diǎn)的各種方法?!?/strong>

2. 文件鎖簡介

「一般來說,有兩種鎖」:

  • 獨(dú)占鎖——也稱為寫鎖
  • 共享鎖——也稱為讀鎖

簡單地說,在寫操作完成時(shí),獨(dú)占鎖防止所有其他操作(包括讀操作)。

相反,共享鎖允許多個(gè)進(jìn)程同時(shí)讀取。讀鎖的目的是防止另一個(gè)進(jìn)程獲取寫鎖。通常,處于一致狀態(tài)的文件確實(shí)應(yīng)該被任何進(jìn)程讀取。

在下一節(jié)中,我們將看到Java如何處理這些類型的鎖。

3. Java中的文件鎖

Java NIO庫支持在操作系統(tǒng)級別鎖定文件。FileChannel 中的lock() 和*tryLock()*方法就是為了這個(gè)而存在。

我們可以通過 FileInputStream, FileOutputStream,RandomAccessFile 來獲取FileChannel,三者均可通過 getChannel() 方法返回 FileChannel對象.

或者, 我們可以直接通過靜態(tài)方法 open 來創(chuàng)建 FileChannel  :

try (FileChannel channel = FileChannel.open(path, openOptions)) {
  // write to the channel
}

接下來,我們將回顧在Java中獲取獨(dú)占鎖和共享鎖的不同方式。要了解有關(guān)文件通道的更多信息,請查看[Guide to Java FileChanne 教程。

4. 獨(dú)占鎖

正如我們已經(jīng)了解到的,在寫入文件時(shí),「我們可以使用獨(dú)占鎖」防止其他進(jìn)程讀取或?qū)懭胛募?/p>

我們通過調(diào)用 FileChannel 類上的 lock() 或 tryLock()) 來獲得獨(dú)占鎖。我們還可以使用它們的重載方法:

  • lock(long position, long size, boolean shared)
  • tryLock(long position, long size, boolean shared)

在這些情況下,shared參數(shù)必須設(shè)置為false。

要獲得獨(dú)占鎖,必須使用可寫的文件通道。我們可以通過 FileOutputStream 或 RandomAccessFile 的 getChannel() 方法創(chuàng)建它?;蛘?,如前所述,我們可以使用 FileChannel 類的靜態(tài)方法:open。我們只需要將第二個(gè)參數(shù)設(shè)置為StandardOpenOption.APPEND :

try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND)) { 
    // write to channel
}

4.1. 使用 FileOutputStream 的獨(dú)占鎖

從 FileOutputStream 創(chuàng)建的 FileChannel 是可寫的。因此,我們可以獲得一個(gè)獨(dú)占鎖:

try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/testfile.txt");
     FileChannel channel = fileOutputStream.getChannel();
     FileLock lock = channel.lock()) { 
    // write to the channel
}

    在這里,channel.lock() 要么阻塞直到獲得一個(gè)鎖,要么拋出一個(gè)異常。例如,如

  • 果指定的區(qū)域已鎖定,則會引發(fā)OverlappingFileLockException。有關(guān)可能的異常的完整列表,請參見Javadoc。我們還可以使用 channel.tryLock() 執(zhí)行非阻塞鎖。如果由于另一個(gè)程序持有一個(gè)重疊的鎖而無法獲取鎖,則返回null。如果由于任何其他原因未能執(zhí)行此操作,則會引發(fā)相應(yīng)的異常。

4.2. 使用 RandomAccessFile 的獨(dú)占鎖

使用 RandomAccessFile,我們需要設(shè)置 [constructor](https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#RandomAccessFile(java.io.File, java.lang.String)) 方法的第二個(gè)參數(shù)。

在這里,我們將使用讀寫權(quán)限打開文件:

try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "rw");
      FileChannel channel = file.getChannel();
      FileLock lock = channel.lock()) {
    // write to the channel
}

如果我們以只讀模式打開文件,并嘗試向其通道進(jìn)行寫入操作,將會拋出 NonWritableChannelException 異常。

4.3.獨(dú)占鎖依賴于可讀的 FileChannel

如前所述,獨(dú)占鎖需要一個(gè)可寫通道。因此,我們無法通過從 FileInputStream 創(chuàng)建的 FileChannel 獲得獨(dú)占鎖:

try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "rw");
      FileChannel channel = file.getChannel();
      FileLock lock = channel.lock()) {
    // write to the channel
}

在上面的例子中,lock() 方法將拋出一個(gè) nonwriteablechannelexception 。實(shí)際上,這是因?yàn)槲覀冋趯σ粋€(gè)創(chuàng)建只讀通道的 FileInputStream 調(diào)用 getChannel。這個(gè)例子只是為了證明我們不能寫到一個(gè)不可寫的通道。事實(shí)上,我們不會捕捉并重新拋出異常。

5.  共享鎖

記住,共享鎖也稱為讀 鎖。因此,要獲得讀鎖,我們必須使用可讀的文件通道。

這樣的 FileChannel 可以通過調(diào)用 FileInputStream 或 RandomAccessFile 上的 getChannel() 方法獲得。同樣,另一個(gè)選項(xiàng)是使用 FileChannel 類的靜態(tài) open 方法。在這種情況下,我們將第二個(gè)參數(shù)設(shè)置為 StandardOpenOption.READ 。

try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "rw");
      FileChannel channel = file.getChannel();
      FileLock lock = channel.lock()) {
    // write to the channel
}

這里要注意的一點(diǎn)是,我們選擇通過調(diào)用 lock(0, Long.MAX_VALUE, true) 來鎖定整個(gè)文件。通過將前兩個(gè)參數(shù)更改為不同的值,我們還可以只鎖定文件的特定區(qū)域。對于共享鎖,第三個(gè)參數(shù)必須設(shè)置為true。

為了簡單起見,我們將在下面的所有示例中鎖定整個(gè)文件,但請記住,我們始終可以鎖定文件的特定區(qū)域。

5.1. 使用 FileInputStream 中的共享鎖

從 FileInputStream 獲得的 FileChannel 是可讀的。因此,我們可以獲得一個(gè)共享鎖:

try (FileInputStream fileInputStream = new FileInputStream("/tmp/testfile.txt");
    FileChannel channel = fileInputStream.getChannel();
    FileLock lock = channel.lock(0, Long.MAX_VALUE, true)) {
    // read from the channel
}

在上面的代碼片段中,將成功調(diào)用通道上的 lock() 。這是因?yàn)楣蚕礞i只要求通道是可讀的就行。

5.2. 使用 RandomAccessFile中的共享鎖

這次,我們只需要使用 ''讀" 權(quán)限打開文件即可:

try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "r"); 
     FileChannel channel = file.getChannel();
     FileLock lock = channel.lock(0, Long.MAX_VALUE, true)) {
     // read from the channel
}

在本例中,我們創(chuàng)建了一個(gè)具有讀取權(quán)限的RandomAccessFile對象,然后從中創(chuàng)建一個(gè)可讀通道,從而創(chuàng)建一個(gè)共享鎖。

5.3. 共享鎖依賴于可讀的 FileChannel

因此,我們無法通過從 FileOutputStream 創(chuàng)建的 FileChannel 獲取共享鎖:

Path path = Files.createTempFile("foo","txt");
try (FileOutputStream fis = new FileOutputStream(path.toFile()); 
    FileLock lock = fis.getChannel().lock(0, Long.MAX_VALUE, true)) {
    // unreachable code
} catch (NonWritableChannelException e) { 
    // handle exception
}

在本例中,調(diào)用 lock() 嘗試獲取從 FileOutputStream 創(chuàng)建的通道上的共享鎖。這樣的通道是只寫的。它不能滿足通道必須可讀的需要。這將觸發(fā)一個(gè)NonWritableChannelException。

同樣,這段代碼只是為了證明我們不能從一個(gè)不可讀的通道中讀取。

6. 思考

實(shí)際上,使用文件鎖是困難的;鎖定機(jī)制是不可移植的。我們需要考慮到這一點(diǎn)來設(shè)計(jì)鎖定邏輯。

在POSIX系統(tǒng)中,鎖是建議性的。讀取或?qū)懭虢o定文件的不同進(jìn)程必須就鎖定協(xié)議達(dá)成一致。這將確保文件的完整性。操作系統(tǒng)本身不會強(qiáng)制任何鎖定。

在Windows上,除非允許共享,否則鎖將是獨(dú)占的。討論操作系統(tǒng)特定機(jī)制的優(yōu)點(diǎn)或缺點(diǎn)超出了本文的討論范圍。然而,在實(shí)現(xiàn)鎖定機(jī)制時(shí),了解這些細(xì)微差別很重要。

7. 總結(jié)

在本教程中,我們回顧了在Java中獲取文件鎖的幾種不同選項(xiàng)。

首先,我們首先了解兩種主要的鎖定機(jī)制,以及Java NIO庫如何促進(jìn)鎖定文件。然后,我們?yōu)g覽了一系列簡單的示例,這些示例顯示我們可以在應(yīng)用程序中獲得獨(dú)占和共享鎖。我們還研究了使用文件鎖時(shí)可能遇到的典型異常類型。 

到此,相信大家對“Java中怎么鎖文件”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI