繁体   English   中英

多线程环境中的mkdirs()函数

[英]mkdirs() function in multithreaded environment

我正在创建文件和文件夹树。 我正在改写多线程。 我看到的唯一弱点是创建文件夹时。 现在它一个接一个(深入)。 在我写下文件之前,我会检查路径是否存在。 如果没有,我使用mkdirs来创建所有缺失的东西。

public void checkDir(String relativePath) {
        File file = new File(homePath + relativePath);
        if (!file.exists()) {
            if (file.mkdirs()) {
                log.info("Directory: " + homePath + relativePath + " is created!");
            } else {
                log.error("Failed to create directory: " + homePath + relativePath + " !");
            }
        }
    }

我有一个问题,当我使用两个线程时会发生什么。 一个有A / B / C路径,另一个有A / B / D. 假设我只有一个文件夹但不存在B.所以他们都会检查路径是否存在并且想要创建它。 所以其中一个可能会失败,因为另一个会更快。 那么我该如何管理呢?

  1. 我正在考虑删除存在的条件并让它失败但是没有AlreadyExists异常我可以抓住..
  2. 首先创建目录树(但我认为会有更好的方法吗?)
  3. 将目录创建作为关键部分并使其顺序 - 不确定如何在春季执行此操作,但无论如何确定它是必要的并且不会太慢地减慢过程。

也许我过分思考,但从理论上讲,这种情况可能会发生。 目前我使用常规Thread,但我想使用spring TaskExecutor。 它自己处理关键部分,但这不是共享变量或任何东西,路径是不同的,所以我认为它不会识别它。

谢谢你的建议。

指定File.mkdirs()方法以创建目录及其所有父目录(如果它们不存在)。 ERGO有呼吁没有点exists(). 无论如何都会检查存在性。 调用exists()只是浪费时间。 mkdirs()本质上是一个原子操作:试图超越它是没有意义的。

请注意,返回值false不一定是失败。 它可能只是表明路径中的所有目录都已存在。

基本上你的问题的前提是错误的。

这些答案似乎都没有解决mkdirs()是否是线程安全的问题,一个答案表明mkdirs()是原子的,但可能存在失败的情况。 这个函数基本上处理文件系统,所以它可能涉及对相应主机上的操作系统的系统调用,如果你还不知道你的应用程序将会知道目标系统,那么确定这些系统调用是否实际上是线程安全的是不可能的。用于。

例如,即使mkdirs()在创建文件夹结构之前检查是否存在,在以下情况下会发生什么,

线程1调用mkdirs(),它本身检查文件夹结构的存在并确定它不存在。 那时,线程1被抢占了。

线程2调用mkdirs(),它本身检查文件夹结构的存在并确定它不存在,然后继续创建文件夹结构。

线程1再次启动并继续尝试创建文件夹结构,之前确定它之前不存在。

那里发生了什么? 我不知道,这一系列事件很难测试,特别是知道创建文件夹系统调用在操作系统之间有所不同。 对于线程安全而言,最好的选择是避免引入可能难以跟踪和调试的错误,这将是在代码中的这个关键部分实现一定程度的互斥。

我想这很容易采取一种天真的方法并声明两个线程都可以访问的单个“全局”变量,例如布尔值b,然后在关键部分周围添加以下代码,

synchronized(b) {
     // Your critical section here
}

这将保证如果一个线程已经锁定b,它只能在另一个线程等待时访问临界区,从而确保两个线程都不会调用mkdir()。

但是,如果您想了解有关多线程以及如何在较低级别实现互斥的更多信息,在这种情况下,我建议您查看信号量以及如何实现这些信号量来解决此问题。

正如EJP所指出的, false的回报可能意味着许多事情,一些错误,一些错误。 如果你想记录它实际上无法创建目录的事实,你应该检查之后是否存在:

public final class DirectoryHelper {
   private DirectoryHelper(){}

   public static boolean createDirectories(File path) {
      if (path.mkdirs()) return true; //definitely has new dir
      // if false, just look afterwards for the existence of the directory
      // also opportunity to throw own exceptions if you prefer
      return path.exists() && path.isDirectory();
   }
}

我在这里写了一个新方法,只有当目录不存在之后才返回false。 我不在乎它是否已经制作或存在。 由于新订单,我也不需要synchronized块。

您的代码如下所示:

public void checkDir(String relativePath) {
    File file = new File(new File(homePath), relativePath);
    if (!file.exists()) { // just to prevent logging of existing dirs
        if (DirectoryHelper.createDirectories(file)) {
            log.info("Directory: " + file + " is created!");
        } else {
            log.error("Failed to create directory: " + file + " !");
        }
    }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM