Java NIO FileLock.release()报ClosedChannelException及文件截断问题
问题根因说明
你遇到的两个现象都和FileLock本身的逻辑无关,是API使用方式和语法执行顺序的问题:
文件内容被清空的原因
FileLock没有截断文件的能力,清空文件是FileOutputStream的默认行为:
- 调用
new FileOutputStream(path)单参数构造方法创建输出流时,JVM打开文件的默认操作就是直接将文件长度截断为0,这一步在流对象创建完成时就已经执行了,和后续是否加锁、加什么类型的锁没有任何关联。 - 如果需要保留文件原有内容,要么使用双参数构造方法
new FileOutputStream(path, true)开启追加模式,要么改用RandomAccessFile按读写模式打开文件后再获取对应的通道。
释放锁抛出ClosedChannelException的原因
这个问题是try-with-resources的执行顺序和资源释放逻辑不匹配导致的:
- 你将
FileChannel声明在try-with-resources的资源块中,当try块内的加锁代码执行完成后,会自动触发ch.close()关闭通道,而文件通道关闭时,会自动释放该通道上绑定的所有文件锁。 - 等执行流程走到你手写的
finally代码块时,通道已经处于关闭状态,此时再调用lock.release()操作和已关闭通道绑定的锁对象,自然会抛出ClosedChannelException。
正确写法参考
把FileLock也纳入try-with-resources的资源管理范围,让资源按「先获取的后释放」的顺序自动关闭,不需要手动写finally释放:
import java.io.*; import java.nio.channels.*; public class FileLockTest{ public static void main(String[] args){ // 用RandomAccessFile以读写模式打开,不会默认截断文件 try(RandomAccessFile raf = new RandomAccessFile(args[0], "rw"); FileChannel ch = raf.getChannel(); FileLock lock = ch.lock()) // 锁也交给try-with-resources管理,自动释放 { // 此处编写持有锁期间的文件读写逻辑 }catch(FileNotFoundException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } }
补充说明:文件锁是和整个JVM进程绑定的,同一个JVM内的不同线程/通道持有同一文件的锁不会互斥,锁的互斥效果只作用在不同进程之间。
内容的提问来源于stack exchange,提问作者Troskyvs
相关产品推荐
相关产品推荐

