当前位置: 首页 > 知识库问答 >
问题:

CompletableFuture将结果收集到hashmap

公冶浩慨
2023-03-14

我正在从数据库中读取pdf文件列表,对它们进行解析,并用它们执行一些任务
当我阅读这个pdf列表时,我发现从pdf中提取图像需要花费更多的时间,而且我不需要阻止我的主线程来阅读图像。所以我想在一个单独的线程中执行提取图像
我想从一个又一个pdf中读取图像,而不是一次将所有pdf加载到内存中(由于内存问题)。所以我只想要两条线;一个应该是主线程(从pdf中读取一些文本并执行其他操作),另一个应该是提取图像并返回图像对象集的线程。

这里的一个警告是,来自pdfs的图像在其内容中可能是相同的,所以我想在收集结果之前使用校验和或其他方法删除重复的图像。
我不想在内存中保存图像,直到所有任务完成,我当我得到一个pdf的结果时,想要删除重复的文件

所以真正的问题是,我需要向大小为1的线程池提交多个任务,并且需要在得到结果时删除重复项,这样我就不需要在内存中保存更长时间的映像。


我已经从代码中删除了不必要的东西,比如图像及其内容,并将代码转换为基于字符串的问题。

public static void main(String[] args) throws InterruptedException, ExecutionException {
        Map<String, Integer> uniqueImages = new HashMap<>();
         ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(1);
        List<CompletableFuture<String>> futureList = new ArrayList<>();
        for(int i = 0; i<20000; i++) {
            CompletableFuture<String> obj = CompletableFuture.supplyAsync(()->{
                //Assume lot of duplicates
                return UUID.randomUUID().toString();
            }, newFixedThreadPool).thenApply((x)->{
                if(uniqueImages.containsKey(x)) {
                    int val = uniqueImages.get(x);
                    uniqueImages.put(x, val+1);
                }
                else {
                    uniqueImages.put(x, 1);
                }
                return x;
            });
            futureList.add(obj);
        }
        
        for(CompletableFuture<String> future: futureList) {
            future.get();
        }
        System.out.println(uniqueImages.size());
    }

我担心这段代码是否真的有效或引发ConcurrentModification异常

  • 是否uniqueImagesmap真的包含唯一的图像及其计数?
  • 有什么隐藏的问题吗?
  • 有更好的方法来解决我的用例吗?

共有1个答案

嵇永望
2023-03-14

只要您只使用大小为1的线程池,就没有问题。

但是,如果有多个线程,那么代码确实不是线程安全的,并且容易出现数据竞争。
我们可以使用以下场景进行演示:

考虑以下代码:

if(uniqueImages.containsKey(x)) {
    int val = uniqueImages.get(x);
    uniqueImages.put(x, val+1);
}
else {
    uniqueImages.put(x, 1);
}

想象线程1和线程2都返回相同的字符串,并到达行if(uniqueImages.containsKey(x))在一起。
if将在两个线程中返回false,并且uniqueImages.put(x,1);将在两个线程中被调用
可能会抛出一个Con电流修改异常,或者您会得到一个错误的计数(1而不是2)。

如果计划使用多个线程,则必须使用ConcurrentHashMap

 类似资料:
  • 我必须运行多个外部调用操作,然后以列表的形式获得结果。我决定使用api,而我准备的代码相当恶心: 示例: 我有以下几个问题: > 我可以避免在流中重复块吗?在流中我将CompletableFuture映射到User? 此代码是否可以不那么连续(如何避免等待所有的未来完成?) 这样做可以吗(所有的未来都将在流中解决吗?):

  • 问题内容: 我知道这应该是简单的,我可能正直盯着问题,但我再次陷入困境,需要代码专家的帮助。 我试图从jdbc的一列中取出一行,并将它们放入数组中。 我这样做如下: creatConnection是已经定义的方法,可以执行其明显的工作。我在创建另一个结果集的同时创建了我的结果集,我将该列的字符串存储到一个数组中。然后打印出来以备不时之需。还要确保它在那里。 问题在于其将整个列存储到contactL

  • 我有一个用户类,有16个属性,比如名字,姓氏,出生日期,用户名,密码等...这些都存储在MySQL数据库中,当我想要检索用户时,我使用ResultSet。我想将每一列映射回用户属性,但我这样做的效率似乎非常低。例如,我正在做: 也就是说,我检索所有的列,然后通过将所有的列值插入用户构造函数来创建用户对象。 有人知道更快、更整洁的方法吗?

  • 问题内容: 我正在使用以下内容将检索到的值添加到类中。所有值都将添加到该类的属性中,但是我正在使用compisition(在类中具有class的对象),并且在输出中不显示任何内容。 地址类别如下: 问题答案: 像这样的作品: 将ResultSet行转换为JavaBean。此实现使用反射和BeanInfo类将列名与bean属性名匹配。属性根据以下几个因素与列匹配: 该类具有与列同名的可写属性。名称比

  • 我需要帮助将结果集值从servlet转发到jsp,而不使用JSTL实现 工作流程: 用户在输入框中输入值并单击搜索按钮 单击搜索时会调用servlet。servlet专注于数据库实现并将结果集值转发到请求所在的同一jsp页面。 问题:我的结果集大小是3,但仅表顶部的值就打印在我的jsp页面中。其余2个值缺失。我希望所有的值都打印在我的jsp页面中。 这是我的代码: Productlist.jsp

  • 但是由于某种原因,当我运行我的程序时,它似乎没有完全接受输入,并且给我一个错误的答案,当按下按钮时,它给我的答案是179.0的男性和169.0的女性。 我看了一遍又一遍,似乎无法找出这个逻辑错误。这是我的代码。