Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么mkdir()有时不起作用?_Java_Multithreading_Mkdir - Fatal编程技术网

Java 为什么mkdir()有时不起作用?

Java 为什么mkdir()有时不起作用?,java,multithreading,mkdir,Java,Multithreading,Mkdir,我编写这个程序是为了测试mkdir()失败的场景。为什么会失败 有时效果很好,有时我会: 无法创建目录::myDir4 无法创建目录::myDir4 最后我发现每个目录都被创建了 在每次测试中,我都会删除所有创建的目录 我尝试这样做是因为在我的项目中有100个线程试图测试和创建这样的目录。。。同样的失败 public class DFS { static long time1 = System.currentTimeMillis(); public static void mai

我编写这个程序是为了测试
mkdir()
失败的场景。为什么会失败

有时效果很好,有时我会:

无法创建目录::myDir4 无法创建目录::myDir4

最后我发现每个目录都被创建了

在每次测试中,我都会删除所有创建的目录

我尝试这样做是因为在我的项目中有100个线程试图测试和创建这样的目录。。。同样的失败

public class DFS {
    static long time1 = System.currentTimeMillis();
    public static void main(String a[]) {
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
        new Thread(new CreteDir()).start();
    }
}

class CreteDir implements Runnable {
    public void run() {
        //Object obj = new Object();
        synchronized (this) {
        if(System.currentTimeMillis() - DFS.time1 > 10) {
            try {
                this.wait();
            }
            catch(InterruptedException ie) {
                ie.printStackTrace();
            }
        }
        File f1 = new File("myDir1");
        File f2 = new File("myDir2");
        File f3 = new File("myDir3");
        File f4 = new File("myDir4");
        File f5 = new File("myDir5");

        if (!f1.exists()&&!f1.mkdir()) {
            System.out.println("Cannot create DIR :: "+f1.getName());
        }
        if (!f2.exists()&&!f2.mkdir()) {
            System.out.println("Cannot create DIR :: "+f2.getName());
        }
        if (!f3.exists()&&!f3.mkdir()) {
            System.out.println("Cannot create DIR :: "+f3.getName());
        }
        if (!f4.exists()&&!f4.mkdir()) {
            System.out.println("Cannot create DIR :: "+f4.getName());
        }
        if (!f5.exists()&&!f5.mkdir()) {
            System.out.println("Cannot create DIR :: "+f5.getName());
        }
        this.notifyAll();
        }
    }
}

你有比赛条件

每个线程尝试检查每个目录,如果它还不存在,则创建它。发生的事情是这样的:

// Test first without locking to reduce the concurrency bottleneck
if (!dir.exists()) {
    synchronize (globalDirLock) {
        // Repeat the test while holding the lock
        if (!dir.exists()) { 
            if (!dir.mkdir()) {
                System.out.println("OOOPS!");
            }
        }
    }
}
  • 线程
    A
    测试
    myDir4
    并发现它不存在
  • 线程
    B
    测试
    myDir4
    并发现它不存在
  • 线程
    A
    创建
    myDir4
    。。。成功
  • 线程
    B
    创建
    myDir4
    。。。失败!它已经存在了
这可能发生在任何目录中。。。或者根本不是。。。具体取决于操作系统如何安排Java线程,等等


您的代码正试图在此上进行同步,但该尝试无效。
this
将是当前线程正在使用的
CreteDir
的实例。。。但是每个线程都有一个不同的实例,因此实际上没有线程间同步。为了有效地同步,所有线程都需要在同一个对象上同步。。。但这会使多线程变得无效,因为粒度是错误的

事实上,您需要重新考虑整个多线程策略。事实上,这不是“真正的代码”,这意味着我们不能真正建议你如何去做

从你上次评论的字里行间,我认为你有三种可能的策略:

  • 当目录不存在时,只需使用“全局”锁来同步目录的创建。大概是这样的:

    // Test first without locking to reduce the concurrency bottleneck
    if (!dir.exists()) {
        synchronize (globalDirLock) {
            // Repeat the test while holding the lock
            if (!dir.exists()) { 
                if (!dir.mkdir()) {
                    System.out.println("OOOPS!");
                }
            }
        }
    }
    
  • 创建内存中的数据结构,每个目录有一个(锁)对象。需要仔细填充该数据结构,以避免两个同时的客户端请求最终为单个目录创建两个锁对象的争用情况

    (如果稍微调整一下此方案,您可能还可以使用lock对象的存在性来避免重复检查目录是否存在。此检查涉及系统调用,并且在处理器开销方面非常重要。)

  • 只需忽略
    File.mkdir()
    返回
    false
    的情况。(可能会执行另一个
    File.exists()
    File.isDirectory()
    测试…以防万一。)


您可以尝试以下操作,而不是添加全局锁:

if (!f1.exists()&&!f1.mkdir()&&!f1.isDirectory()) {
            System.out.println("Cannot create DIR :: "+f1.getName());
        }

isDirectory()
将告诉我是否已经创建了此目录。

有时我会收到消息Cannot create DIR::myDir1 Cannot create DIR::myDir2我认为这是由于一个线程测试DIR存在,并在mkdir操作之前得到false,其他线程创建DIR。。。mkdir操作的当前线程收到此失败消息..可能目录已经存在?@Kamil。。。是 啊这只是打字错误。。。但是对于代码来说,这不是一个问题,
synchronized(this)
没有任何意义。在这种情况下,
这个
只能由一个线程访问。同时运行几个线程试图创建相同的目录也没有任何意义。。。