我有一个Java应用程序遍历树状文件夹结构并最终删除整个文件夹结构。为此,我使用Blocking Queue
和一个生产者(遍历树并将路径放到需要删除的文件)和许多实际执行删除作业的消费者。
文件夹必须为空才能被删除,因此,请考虑使用以下结构:
/folder1/file1
/folder1/file2
/folder1/file3
/folder1/
这是BlockingQueue
在任何给定点可能包含的内容。考虑到有4个消费者轮询队列:
Consumer1将选择并删除/folder1/file1
Consumer2将选择并删除/folder1/file2
Consumer3将选择并删除/folder1/file3
Consumer4将选择并删除/folder1
如果Consumer3没有完成删除/folder1/file3
,则Consumer4将无法删除/folder1/
,因为它将被标记为非空。
消费者线程是否有办法等待其他消费者线程完成某些任务?
答案 0 :(得分:2)
解决业务问题的方法有很多种。
方法1:您的问题是当Consumer 4实际上到达Folder时,它需要等待删除所有文件。我认为消费者4如果可以访问folder1,则无需这样做。它只能转到文件夹(操作系统路径)并检查它是否为空。如果没有则删除它,如果没有则等待。
方法2:您的生产者线程可以做更多的工作。如果它发现需要在folder1中删除所有文件。它不需要放置所有文件名,然后放置文件夹名称。它应该只是放置文件夹名称。只有一个消费者线程将获取文件夹名称并将其删除。
答案 1 :(得分:1)
这是另一种方法。我假设在Folder1的所有文件排队后,Folder1将被排队。这里的技巧是每当Consumer线程获取文件时,将Thread Name更改为File Name。现在,当消费者线程(消费者4)来删除目录Folder1时,它将检查所有具有名称" Folder1"的执行线程。在他们。如果找到任何,那么它将等待完成。我有以下代码示例..如有任何问题,请告诉我
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
public class DeleteFilesAndFolders
{
public void executeSomeTasks() throws InterruptedException
{
ExecutorService executor = Executors.newFixedThreadPool(5);
List<DeleteTask> tasks = createSomeDummyTasks();
for (DeleteTask t : tasks) {
executor.submit(t);
}
executor.shutdown();
}
private List<DeleteTask> createSomeDummyTasks()
{
List<DeleteTask> tasks = new ArrayList<>();
tasks.add(new DeleteTask("/good/folder/file1"));
tasks.add(new DeleteTask("/good/folder/file2"));
tasks.add(new DeleteTask("/good/folder/file3"));
tasks.add(new DeleteTask("/good/folder/file4"));
tasks.add(new DeleteTask("/good/folder/file6"));
tasks.add(new DeleteTask("/good/folder/file7"));
tasks.add(new DeleteTask("/good/folder/file9"));
tasks.add(new DeleteTask("/good/folder/file8"));
tasks.add(new DeleteTask("/good/folder"));
return tasks;
}
public static class DeleteTask implements Callable<String>
{
volatile String fileNameToDelete;
public DeleteTask(String fileNameToDelete)
{
this.fileNameToDelete = fileNameToDelete;
}
@Override
public String call() throws Exception
{
// Just checking if it is a directory
if (fileNameToDelete.equalsIgnoreCase("/good/folder")) {
waitForDeletionOfChildFiles(fileNameToDelete);
}
String originalName = Thread.currentThread().getName();
Thread.currentThread().setName(fileNameToDelete);
Thread.sleep(20000);
Thread.currentThread().setName(originalName);
return null;
}
private void waitForDeletionOfChildFiles(String directoryName) throws InterruptedException
{
while (true) {
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
List<Thread> anyChildThreads = threadSet.stream()
.filter(p -> p.getName().contains(directoryName))
.collect(Collectors.toList());
if (!anyChildThreads.isEmpty()) {
System.out.println(
" Some Child threads still Running. I should be waiting !!");
anyChildThreads.stream().forEach(x -> {
System.out.println(x.getName());
});
} else {
System.out.println(
" All Done.. no wait clean this directory !!");
break;
}
Thread.sleep(5000);
}
}
}
public static void main(String args[]) throws InterruptedException
{
DeleteFilesAndFolders et = new DeleteFilesAndFolders();
et.executeSomeTasks();
}
}