在多線程的環(huán)境下,如果兩個線程操作相同的競爭區(qū),需要使用鎖來保證線程安全。在Java中有多種選擇,如Synchronized關(guān)鍵字,CountDownLatch等等。但是這些方式,在多進(jìn)程的情況下,會失效。
那么在多進(jìn)程情況下,我們怎么做進(jìn)程同步呢?答案是文件鎖。Java提供的FileLock類,可以實現(xiàn),下面來看看具體的用法。
FileLock API
public abstract FileLock lock(long position, long size, boolean shared) throws IOException;
public final FileLock lock() throws IOException;
public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException;
public final FileLock tryLock() throws IOException;
方法:
-
lock方法,會block住線程,直到獲取到鎖。 -
tryLock方法,不會block,會直接返回,如果能獲取到鎖,則返回FileLock對象,如果獲取不到鎖,返回null。
參數(shù):
-
position:鎖定文件中的開始位置 -
size:鎖定文件中的內(nèi)容長度 -
shared:是否使用共享鎖。true為共享鎖;false為獨占鎖。- 共享鎖:允許其他進(jìn)程同時獲取
- 獨占鎖:不允許其他進(jìn)程同時獲取
使用示例
進(jìn)程1
public static void main(String[] args) {
try {
// 打開文件
FileOutputStream raf = new FileOutputStream("lock.txt");
// 獲取FileChannel
FileChannel channel = raf.getChannel();
// 獲取FileLock,上鎖
FileLock lock = channel.lock();
Thread.sleep(10000);
// 手動釋放FileLock
lock.close();
} catch (Exception e) {
e.printStackTrace();
}
}
進(jìn)程1啟動后,會獲取FileLock鎖,然后持有鎖Sleep 10s。
進(jìn)程2:
public static void main(String[] args) {
try {
FileOutputStream raf = new FileOutputStream("lock.txt");
FileChannel channel = raf.getChannel();
// 會被block,直到獲得鎖
FileLock lock = channel.lock();
// 如果沒有獲得鎖,直接返回null,不會被block
lock = channel.tryLock();
} catch (Exception e) {
e.printStackTrace();
}
}
此時進(jìn)程2啟動:
- 如果調(diào)用
lock方法,會block線程,直到進(jìn)程1釋放鎖。 - 如果調(diào)用
tryLock方法,不會block,會直接返回,如果能獲取到鎖,則返回FileLock對象,如果獲取不到鎖,返回null。
總結(jié)
FileLock可以用于Android中多進(jìn)程同步,有以下幾點需要注意:
- 如果同一個進(jìn)程中的不同線程,同時對一個文件進(jìn)行加鎖操作,會直接拋出異常:
java.nio.channels.OverlappingFileLockException。 -
FileLock釋放的條件是,手動調(diào)用release/close釋放,或JVM終止運行。 - 本質(zhì)也是調(diào)用
Linux的fnctl來從內(nèi)核對文件進(jìn)行加鎖。 - 同一個
FileChannel只能被使用一次,如果調(diào)用close之后,再去調(diào)用lock,會報ClosedChannelExcption。