2

以下方法不访问任何共享变量。它仍然不是线程安全的。我要么测试错了,要么我遗漏了一些东西。请解释。

方法:

public static boolean acquireFolderLock(File directoryPath) {
    final String LOCK_FILE_NAME = ".lock";
    boolean isLocked = false;
    if(directoryPath != null && directoryPath.isDirectory()) {
        File lockFile = new File(new StringBuilder(directoryPath.getAbsolutePath()).append(File.separatorChar).append(LOCK_FILE_NAME).toString());
        if(lockFile.exists()) {
            isLocked = false;
        } else {
            try {
                lockFile.createNewFile();
                isLocked = true;
            } catch(IOException ioex) {
                isLocked = false;
            }
        }
    }
    return isLocked;
}

用于测试的线程类

class AThread extends Thread {
String name;
public AThread(String name) {
    this.name = name;
}

@Override
public void run() {
    File f = new File("C:\\TEMP\\DIRECTORY");
    System.out.println(name + ": " + Util.acquireFolderLock(f));
}
}

以及启动线程的主要方法

public static void main(String[] args) throws Exception {
    for(int i = 1; i <= 100; i++) {
        (new AThread("Thread-->" + i)).start();
    }
}
4

4 回答 4

6

该方法检查文件是否存在,然后创建它。这意味着当另一个线程正在执行时,一个线程可能已经完成了该语句if (lockFile.exists())(结果: ) (因此,它创建了锁定文件)。falselockFile.createNewFile();

第一个线程现在基于不正确的信息继续:它认为该文件不存在,但它已由另一个线程创建。

线程安全不仅仅关乎共享变量,还关乎共享资源(变量、数据库、文件系统、网络连接等)。

于 2012-04-06T22:08:04.497 回答
3

“静态”是一个包含文件系统的术语。仅仅因为没有明确共享变量并不意味着文件系统不在线程之间共享。

访问文件系统,就像您在这里所做的那样,与访问共享变量一样糟糕,并且需要相同的技术来确保线程安全。

于 2012-04-06T22:06:25.363 回答
0

根据 javadocs for File.createNewFile() http://docs.oracle.com/javase/6/docs/api/java/io/File.html#createNewFile ()

注意:此方法不应用于文件锁定,因为生成的协议不能可靠地工作。应该改用 FileLock 工具。

所以你应该使用 java.nio.channels.FileLock,它是线程安全的。

于 2012-04-06T22:11:16.457 回答
0

你应该检查 lockFile.createNewFile() 的返回值,你不需要检查 lockFile.exists()

true if the named file does not exist and was successfully created; false if the named file already exists

此外,根据您的用例,nio FileLock 可能比使用 createNewFile 更不可靠。我认为 nio FileLock 在 NFS 上被破坏了。我不确定 javadocs 中的不可靠是什么意思,但 createNewFile 的一个问题是当你崩溃时你会离开锁。不过,这可能是一项功能而不是错误,具体取决于您的用例。

于 2012-04-06T23:08:46.130 回答