在别人可以开始之前等待消费者完成任务

时间:2017-03-20 16:29:15

标签: java multithreading producer-consumer blockingqueue

我有一个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/,因为它将被标记为非空。

消费者线程是否有办法等待其他消费者线程完成某些任务?

2 个答案:

答案 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();
}

}