您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Java中怎么鎖文件”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java中怎么鎖文件”吧!
當(dāng)讀寫文件時(shí),需要確保有適當(dāng)?shù)奈募i定機(jī)制,來保證基于并發(fā)I/O應(yīng)用程序的數(shù)據(jù)完整性。
「本教程中, 我們將介紹使用 Java NIO 庫實(shí)現(xiàn)這一點(diǎn)的各種方法?!?/strong>
「一般來說,有兩種鎖」:
簡單地說,在寫操作完成時(shí),獨(dú)占鎖防止所有其他操作(包括讀操作)。
相反,共享鎖允許多個(gè)進(jìn)程同時(shí)讀取。讀鎖的目的是防止另一個(gè)進(jìn)程獲取寫鎖。通常,處于一致狀態(tài)的文件確實(shí)應(yīng)該被任何進(jìn)程讀取。
在下一節(jié)中,我們將看到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 教程。
正如我們已經(jīng)了解到的,在寫入文件時(shí),「我們可以使用獨(dú)占鎖」防止其他進(jìn)程讀取或?qū)懭胛募?/p>
我們通過調(diào)用 FileChannel 類上的 lock() 或 tryLock()) 來獲得獨(dú)占鎖。我們還可以使用它們的重載方法:
在這些情況下,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 }
從 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)的異常。
使用 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 異常。
如前所述,獨(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í)上,我們不會捕捉并重新拋出異常。
記住,共享鎖也稱為讀 鎖。因此,要獲得讀鎖,我們必須使用可讀的文件通道。
這樣的 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ū)域。
從 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只要求通道是可讀的就行。
這次,我們只需要使用 ''讀" 權(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è)共享鎖。
因此,我們無法通過從 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è)不可讀的通道中讀取。
實(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ì)微差別很重要。
在本教程中,我們回顧了在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í)!
免責(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)容。