为什么在一个 JVM 中两次获取 FileLock 会抛出 OverlappingFileLockException?为什么第二个锁的获取不能被阻塞并在释放时获得锁?
4 回答
阻塞 lock() 和非阻塞 trylock() 方法都将抛出 OverlappingFileLockException “如果此 Java 虚拟机已持有与请求区域重叠的锁,或者如果另一个线程已在此方法中阻塞并正在尝试锁定同一文件的重叠区域”,如FileChannel javadoc中所述。
原因是防止死锁。如果另一个线程在尝试获取此锁时已被阻塞,并且您要获取此锁,您接下来可能会尝试获取该其他线程持有的某个锁,从而导致 JVM 内的死锁。如果你试图获取的锁已经被持有,你自己可能已经持有另一个锁,而另一个已经持有这个锁的线程正在尝试获取,再次导致死锁 - 所以抛出异常以提醒你你潜在的编码错误。如果在调用 tryLock() 时发生这种情况,则不会被阻塞,因此不会出现死锁,但可能会陷入尝试获取锁的无限循环。您需要始终以相同的顺序获取锁,那么就不会有死锁的机会,您也不会遇到这种情况,
这意味着您不能为同一个锁依次执行 lock()、tryLock()。如果您已经获得了锁,您应该记住这一点,并且不能再次请求它。
请注意,如果某个其他程序已经持有此锁,则不会抛出异常,并且 tryLock() 将简单地返回 null,而 lock() 将阻塞,直到它可以获取锁(即其他程序已解锁文件区域)。
不,这并不意味着 tryLock() 不是线程安全的。但这意味着您可能需要在代码中捕获和处理 OverlappingFilelLockException,即使这不是声明的异常。
实际上,是您调用获取 FileLock 的方法来确定线程是否阻塞:
FileChannel.lock(...)
将阻塞直到获得锁。FileChannel.tryLock(...)
如果无法获取锁,将立即返回。
它的所有内容都清楚地记录在FileChannel javadoc中。
顺便说一句,@glowcoder 声明的原因是偏离轨道...... NIO 中的“N”代表 New,而不是 Non-blocking。当然,NIO 支持阻塞和非阻塞 I/O。(好吧,也许这只是个玩笑...... :-))
也许是因为它在 NON BLOCKING IO 包中?:-)
这是一个运行时异常,这意味着从技术上讲,它不应该在生产环境中发生,只能在检测错误的开发中发生。
我面临同样的问题,这意味着 FileChannel.Lock/TryLock 不是线程安全的。并且您需要在同一个 JVM 中通过 FileChannel 锁进行同步。ReentranetLock 或 SingleThread 限制。