- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我一直在尝试使用 FileLock
获得对文件的独占访问权限,以便:
因为在 Windows 上(至少)您似乎无法删除、重命名或写入已在使用的文件。我写的代码看起来像这样:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public abstract class LockedFileOperation {
public void execute(File file) throws IOException {
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
try {
// Get an exclusive lock on the whole file
FileLock lock = channel.lock();
try {
doWithLockedFile(file);
} finally {
lock.release();
}
} finally {
channel.close();
}
}
public abstract void doWithLockedFile(File file) throws IOException;
}
下面是一些证明问题的单元测试。您需要在类路径中包含 Apache commons-io 才能运行第三个测试。
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
public class LockedFileOperationTest extends TestCase {
private File testFile;
@Override
protected void setUp() throws Exception {
String tmpDir = System.getProperty("java.io.tmpdir");
testFile = new File(tmpDir, "test.tmp");
if (!testFile.exists() && !testFile.createNewFile()) {
throw new IOException("Failed to create test file: " + testFile);
}
}
public void testRename() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
if (!file.renameTo(new File("C:/Temp/foo"))) {
fail();
}
}
}.execute(testFile);
}
public void testDelete() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
if (!file.delete()) {
fail();
}
}
}.execute(testFile);
}
public void testWrite() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
org.apache.commons.io.FileUtils.writeStringToFile(file, "file content");
}
}.execute(testFile);
}
}
没有一个测试通过。前 2 个失败,最后一个抛出此异常:
java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:247)
at org.apache.commons.io.IOUtils.write(IOUtils.java:784)
at org.apache.commons.io.IOUtils.write(IOUtils.java:808)
at org.apache.commons.io.FileUtils.writeStringToFile(FileUtils.java:1251)
at org.apache.commons.io.FileUtils.writeStringToFile(FileUtils.java:1265)
似乎 lock()
方法在文件上加了一个锁,然后阻止我重命名/删除/写入它。我的假设是锁定文件会给我独占访问文件的权限,这样我就可以重命名/删除/写入它而不必担心是否有任何其他进程也在访问它。
要么我误解了 FileLock
,要么它不是适合我的问题的解决方案。
最佳答案
有关另一个进程的消息仅表示您系统上的某个进程打开了该文件。它实际上并不检查该进程是否恰好与尝试删除/重命名文件的进程相同。在这种情况下,同一程序打开了文件。您已打开它以获取锁。此处的锁几乎没有值(value),尤其是当您为删除或重命名操作执行此操作时。
要执行您想要的操作,您需要锁定目录条目。这在 Java 中不可用,在 Windows 中可能也不可用。这些(删除和插入)操作是原子的。这意味着操作系统负责为您锁定目录和其他文件系统结构。如果另一个进程(或您自己的进程)打开了文件,那么这些操作将失败。如果您试图以独占方式锁定文件(目录条目),而另一个进程(或您自己的进程)打开了该文件,则锁定将失败。没有区别,但尝试锁定只会使操作变得复杂,并且在这种情况下,会使操作变得不可能(也就是说,文件总是在您尝试执行操作之前打开)。
现在写入文件是一个有效的锁定操作。锁定要写入的文件或文件的一部分,然后它将起作用。在 Windows 上,此锁定机制是强制性的,因此另一个打开/文件描述符将无法写入锁定下的任何部分。
编辑
根据 FileChannel.lock
上的 JavaDoc,它与调用 FileChannel.lock(0L, Long.MAXVALUE, false)
相同。这是从第一个字节到最后一个字节的区域的独占锁。
其次,根据 FileLock
上的 JavaDoc
Whether or not a lock actually prevents another program from accessing the content of the locked region is system-dependent and therefore unspecified. The native file-locking facilities of some systems are merely advisory, meaning that programs must cooperatively observe a known locking protocol in order to guarantee data integrity. On other systems native file locks are mandatory, meaning that if one program locks a region of a file then other programs are actually prevented from accessing that region in a way that would violate the lock. On yet other systems, whether native file locks are advisory or mandatory is configurable on a per-file basis. To ensure consistent and correct behavior across platforms, it is strongly recommended that the locks provided by this API be used as if they were advisory locks.
编辑
对于testWrite
方法。公共(public) I/O 静态方法上的 JavaDoc 是稀疏的,但说“如果文件不存在,则将字符串写入创建文件的文件......”并且因为此方法采用 File
而不是打开流,它可能会在内部打开文件。可能它没有打开具有共享访问权限的文件,也没有打开附加访问权限。这意味着现有的打开和锁定(您打开获取锁的 channel )正在阻止该使用。要了解更多信息,您需要获取该方法的源代码并查看它的作用。
编辑
对不起,我纠正了。我检查了 Windows API,文件锁定在 Windows 上是强制性的。这就是写入失败的原因。第一次打开(您的 new RandomAccessFile
)并锁定文件。打开写入字符串成功但写入失败,因为另一个打开(文件描述符)在强制排他锁下具有文件的完整范围 - 也就是说,在释放锁之前没有其他文件描述符可以写入文件。
请注意,锁定与文件描述符相关联不是进程或线程。
关于java - 文件锁是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4025721/
一、公平锁和非公平锁 1.1、公平锁和非公平锁的概述 公平锁:指多个线程按照申请锁的顺序来获取锁。 非公平锁:指在多线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取到锁
阅读目录 1、简介 2、分类 3、全局锁 4、表级锁 5、表锁 6、元数据锁
因此,在我编写的程序中,我有三个函数,为了简单起见,我们将它们称为 A、B 和 C。每个函数都需要访问资源X才能工作。 限制是A和B不允许同时运行并且必须适当同步。但是,C 可以与 A 或 B 同时运
我听说过这些与并发编程相关的词,但是锁、互斥量和信号量之间有什么区别? 最佳答案 锁只允许一个线程进入被锁定的部分,并且该锁不与任何其他进程共享。 互斥锁与锁相同,但它可以是系统范围的(由多个进程共享
这个问题已经有答案了: What is an efficient way to implement a singleton pattern in Java? [closed] (29 个回答) 已关闭
这个问题已经有答案了: What is an efficient way to implement a singleton pattern in Java? [closed] (29 个回答) 已关闭
我对标题中的主题有几个问题。首先,假设我们使用 JDBC,并且有 2 个事务 T1 和 T2。在 T1 中,我们在一个特定的行上执行 select 语句。然后我们对该行执行更新。在事务 T2 中,我们
我希望我的函数只运行一次。这意味着如果多个线程同时调用它,该函数将阻塞所有线程,只允许它运行。 最佳答案 听起来您希望存储过程进行同步。为什么不直接将同步放在应用程序本身中。 pthread_mute
if (runInDemoMode) { lock (this) { //Initalization of tables dCreator.create
我相信无论使用什么语言都可以考虑我的问题,但是为了有一些“ anchor ”,我将使用 Java 语言来描述它。 让我们考虑以下场景:我有一个扩展 Thread 的类 PickyHost 及其实例 p
我知道异步不是并行的,但我现在遇到了一个非常有趣的情况。 async function magic(){ /* some processing here */ await async () =
我们正在使用 Scala、Play 框架和 MongoDB(以 ReactiveMongo 作为我们的驱动程序)构建一个网络应用程序。应用程序架构是端到端的非阻塞。 在我们代码的某些部分,我们需要访问
我需要一个简单的锁,JavaME 超时(concurrent.lock 的反向移植需要完整的 Java 1.3)。 如果其他人已经为 JavaME 发布了经过测试的锁定代码,我宁愿使用它。 锁定是出了
根据 boost : To access the object, a weak_ptr can be converted to a shared_ptr using the shared_ptr co
关于 Mutex 和 Critical 部分之间的区别存在一个问题,但它也不处理 Locks。 所以我想知道临界区是否可以用于进程之间的线程同步。 还有信号状态和非信号状态的含义 最佳答案 在 Win
锁 最为常见的应用就是 高并发的情况下,库存的控制。本次只做简单的单机锁介绍。 直接看代码: 每请求一次库存-1. 假如库存1000,在1000个人请求之后,库存将变为0。
线程和进程 1、线程共享创建它的进程的地址空间,进程有自己的地址空间 2、线程可以访问进程所有的数据,线程可以相互访问 3、线程之间的数据是独立的 4、子进程复制线程的数据 5、子进程启动
**摘要:**细心的你也一定关注到,有的网址是https开头的,有的是http。https开头的网站前面,会有一把小锁。这是为什么呢? 本文分享自华为云社区《还不知道SSL证书已经是刚需了?赶快来了解
试图在 C 中实现一个非常简单的互斥锁(锁)我有点困惑。我知道互斥锁类似于二进制信号量,除了互斥锁还强制执行释放锁的线程的约束,必须是最近获得它的同一线程。我对如何跟踪所有权感到困惑? 这是我到目前为
在阅读了很多与上述主题相关的文章和答案之后,我仍然想知道 SQL Server 数据库引擎在以下示例中是如何工作的: 假设我们有一个名为 t3 的表: create table t3 (a int ,
我是一名优秀的程序员,十分优秀!