Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java CompletableFuture将结果收集到hashmap_Java_Multithreading_Concurrency_Completable Future_Concurrenthashmap - Fatal编程技术网

Java CompletableFuture将结果收集到hashmap

Java CompletableFuture将结果收集到hashmap,java,multithreading,concurrency,completable-future,concurrenthashmap,Java,Multithreading,Concurrency,Completable Future,Concurrenthashmap,我正在从数据库中读取pdf文件列表,并对其进行解析,并使用它们执行一些任务。 当我阅读这个pdf列表时,我看到从pdf中提取图像需要花费更多的时间,我不需要阻止我的主线程来阅读图像。所以我想在一个单独的线程中执行提取图像。 我想从一个又一个pdf文件中读取图像,而不需要一次将所有pdf文件加载到内存中(由于内存问题)。所以我只需要2个线程;一个应该是主线程(从pdf中读取一些文本并执行其他操作),另一个应该是提取图像并返回图像对象集的线程 这里需要注意的一点是,PDF中的图像在内容上可能相同,因

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

这里需要注意的一点是,PDF中的图像在内容上可能相同,因此我希望在收集其结果之前,使用校验和或其他方法删除重复的图像。
我不希望在所有任务完成之前将图像保存在内存中,我希望在获得一个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());
    }
publicstaticvoidmain(String[]args)抛出InterruptedException、ExecutionException{
Map uniqueImages=newhashmap();
ExecutorService newFixedThreadPool=Executors.newFixedThreadPool(1);
List futureList=新建ArrayList();
对于(int i=0;i{
//假设有很多重复的
返回UUID.randomUUID().toString();
},newFixedThreadPool)。然后应用((x)->{
if(uniqueImages.containsKey(x)){
int val=uniqueImages.get(x);
uniqueImages.put(x,val+1);
}
否则{
唯一图像。放置(x,1);
}
返回x;
});
添加(obj);
}
用于(可完成的未来:未来列表){
future.get();
}
System.out.println(uniqueImages.size());
}
我担心这段代码是否真的有效或引发
ConcurrentModification异常

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

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

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

考虑以下代码:

if(uniqueImages.containsKey(x)){
int val=uniqueImages.get(x);
uniqueImages.put(x,val+1);
}
否则{
唯一图像。放置(x,1);
}
假设线程1和线程2都返回相同的字符串,并到达第
if行(uniqueImages.containsKey(x))

if
将在两个线程中返回false,并且
uniqueImages.put(x,1)将在两个线程中调用。
将引发
ConcurrentModification
异常,或者您将得到错误的计数(1而不是2)


如果您计划使用多个线程,那么您必须使用
ConcurrentHashMap

好吧,我肯定会使用
ConcurrentHashMap
代替
HashMap
进行将来的校对。如果您增加线程池中的线程数,那么它通常会给出错误的大小。其次,作为参考,
然后应用
可以在同一线程上执行,也可以不在同一线程上执行。