如何在Java中以线程安全的方式使用mkdirs?

在遇到与mkdirs()相关的问题并且在互联网上发现问题后,我得到mkdirs()存在线程安全问题的印象。

有没有一种方法可以确保当多个线程可能正试图创build类似的文件结构时正确创build目录?

谢谢

(在我的情况下,我将在Android上使用这个)

Solutions Collecting From Web of "如何在Java中以线程安全的方式使用mkdirs?"

好吧,我知道这一段时间以来一直不活跃,但我想也许有一个简单的解决scheme。 你在这个问题的评论中链接的文章似乎表明唯一的问题是目录没有被创build。 解决scheme是这样做的:

 if (!f.mkdirs()) { f.mkdirs(); } 

但是,这似乎效率低下,仍然可能有问题。 那么,为什么不简单地这样做:

 while (!f.mkdirs()) {} 

简单,但它的作品。

编辑:思考了一下后,这个例子可能会滞后遗忘,并可能导致线程locking。 所以,这可能是一个更好的主意:

 while (!f.mkdirs()) { Thread.yield(); } 

当然,只有在可能导致线程locking的线程中,只要不是高优先级的情况,就只能这样做。 把这个放在那里

我不确定Android是否支持并发包,但这是我的看法:

 private static Lock fsLock = new ReentrantLock(); private void mkdir( File dir ) throws FileNotFoundException { if( dir.exists() ) { return; } fsLock.lock(); try { if( !dir.exists() ) { log.info( "Creating directory {}", dir.getAbsolutePath() ); if( !dir.mkdirs() ) { throw new FileNotFoundException( "Can't create directory " + dir.getAbsolutePath() ); } } } finally { fsLock.unlock(); } } 

如果该目录已经存在,该方法返回提前。 如果它不存在,只有一个线程会尝试创build它。

在工作线程中做所有的目录创build,将所有的东西都序列化。 您可以使用LooperHandler来轻松发布调用mkdirs的Runnables到您的工作线程。 当你完成目录时,你可以调用Looper.quit()来处理最后发布的RunnableLooper的文档有示例代码,显示了这么做的近乎微不足道。

一个可能的解决scheme是一个MkDirService(如下所示),只保证一个实例并运行在它自己的线程中。 利用BlockingQueue。

首先服务:

 package mkdir; import java.io.File; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class MkDirService extends Thread { private static MkDirService service; private BlockingQueue<File> pendingDirs = new LinkedBlockingQueue<File>(); private boolean run = true; private MkDirService() { } public synchronized static MkDirService getService() { if (service == null) { service = new MkDirService(); new Thread(service).start(); } return service; } public void makeDir(File dir) { pendingDirs.add(dir); } public void shutdown() { run = false; } @Override public void run() { while (run || !pendingDirs.isEmpty()) { File curDir = null; try { curDir = pendingDirs.take(); } catch (InterruptedException e) { e.printStackTrace(); } if (curDir != null && !curDir.exists()) { curDir.mkdir(); System.out.println("Made: " + curDir.getAbsolutePath()); } } } } 

testing:

 package mkdir; import java.io.File; public class MkDirServiceTest { /** * @param args */ public static void main(String[] args) { MkDirService mdServ = MkDirService.getService(); mdServ.makeDir(new File("test1")); mdServ.makeDir(new File("test1/test2")); mdServ.makeDir(new File("test1/test3")); mdServ.shutdown(); } } 

Eaven如果这个线程有点老了我不知道下面的解决scheme是否有一些错误:

 package service; import java.io.File; public class FileService { public static synchronized boolean mkdirs( File dir ) { return dir.mkdirs(); } }