Java 文件重命名时的线程安全
我对以下代码有一些担心Java 文件重命名时的线程安全,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我对以下代码有一些担心 public class Task implements Runnable { String filePath = "C:\\Backup\\test.xml"; @Override public void run() { File file = new File(filePath); try { System.out.println(Thread.currentThread() + " Renaming " + FileUtil
public class Task implements Runnable {
String filePath = "C:\\Backup\\test.xml";
@Override
public void run() {
File file = new File(filePath);
try {
System.out.println(Thread.currentThread() + " Renaming " + FileUtil.changeFileExtention(file));
Thread.sleep(20000);
System.out.println(Thread.currentThread() + " Renaming Back " + FileUtil.changeFileExtention(file));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面是'FileUtil'是一个类
public class FileUtil {
public static File changeFileExtention(File file) throws Exception {
File newFile = null;
int extIndex = file.getName().lastIndexOf(".");
String ext = getExtentionFromFile(file);
System.out.println("File Extention is [" + ext + "] for file [" + file.getName() + "].");
if (ext.equalsIgnoreCase(".xml")) {
newFile = buildChangedFile(file, extIndex, ".txt");
} else if (ext.equalsIgnoreCase(".proc")) {
newFile = buildChangedFile(file, extIndex, ".xml");
}
file.renameTo(newFile);
return newFile;
}
public static String getExtentionFromFile(File file) throws Exception {
String fileName = file.getName();
int extIndex = fileName.lastIndexOf(".");
if (extIndex != -1) {
return fileName.substring(extIndex);
} else {
String msg = "File extention not found for file [" + fileName + "]";
System.out.println(msg);
throw new Exception(msg);
}
}
private static File buildChangedFile(File file, int extIndex, String targetExtention) throws Exception {
String fileName = file.getName();
File renamedFile = null;
if (file.exists()) {
String newFileName = fileName.substring(0, extIndex) + targetExtention;
System.out.println("New File name -" + newFileName);
String fullPathWithName = file.getParent() + "/" + newFileName;
renamedFile = new File(fullPathWithName);
} else {
String msg = "File not exisit in location [" + file.getAbsolutePath() + "]";
System.out.println(msg);
throw new Exception(msg);
}
return renamedFile;
}
}
这是我的测试课-
public class Test {
public static void main(String[] args) {
Thread thread1 = new Thread(new Task());
Thread thread2 = new Thread(new Task());
Thread thread3 = new Thread(new Task());
thread1.start();
thread2.start();
thread3.start();
}
}
我需要的是,如果一个线程获取了该文件,那么其他线程需要忽略该文件。我不太清楚这里的线程进程,有一些混乱
同步
块中进行重命名过程FileUtil
方法是线程安全的吗Task
类为每个线程创建一个新实例,因此每个线程都应该有自己的文件
对象。既然在这种情况下对象是在堆中创建的,那么它会被共享吗?或者一个线程在堆中有自己的对象堆栈同步
?)非常感谢您帮助我消除困惑。提前感谢大家。显然,如果您有一个文件要更改名称,则不需要多个线程。否则,这就是典型的消费者-生产者问题。作为替代方案,您可以使用blockingQueue结构来使用线程安全。一个(或多个)线程添加到队列的文件名,所有使用者线程都使用一个文件名来更改其名称
您可以检查您可以自己尝试这些东西@UVM-我试过这些东西,但没有弄清楚它是如何工作的。。这就是为什么要向社区寻求帮助。我怀疑任何合理的文件系统都会安全地允许一个重命名,然后拒绝另一个,因为文件名会“丢失”。再说一次,如果有一种简单的方法可以完全避开这个问题,并在任何旧的文件系统上工作,那么为什么还要担心/测试呢?正如您所描述的。无论如何,rename()是如此之快,我可能不会为本地磁盘的线程化而烦恼。但是,对于联网磁盘,我当然会使用排队设计。当遇到实际问题时,特定目录中会有多个文件,并且这些文件将由多个线程动态拾取。我通过在多个线程中硬编码相同的文件名来模拟容易出错的场景。因此,所有线程将拾取相同的文件并尝试重命名它。