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 并发方法设计的数据类型_Java_Multithreading_Collections_Concurrency - Fatal编程技术网

Java 并发方法设计的数据类型

Java 并发方法设计的数据类型,java,multithreading,collections,concurrency,Java,Multithreading,Collections,Concurrency,假设我有一个集合input,其中包含大约100000个对象 有一个线程池,每个线程池都有 获取该集合的一个元素 做一些计算和分析 有时(在大约10%到最多50%的情况下,即每次运行10000到50000次)会将结果添加到输出集合中 处理完输入中的所有项目后,另一个例程获取输出,并对其进行处理 我需要线程池,以便尽可能快地处理输入。输入的每一个元素都应精确处理一次 处理元素的顺序是不相关的(对于输入和输出)输出是只写的-工作人员将只在那里写,不会对输出执行任何其他操作 问题有两个部分,其中线程安全

假设我有一个集合
input
,其中包含大约100000个对象

有一个线程池,每个线程池都有

  • 获取该集合的一个元素
  • 做一些计算和分析
  • 有时(在大约10%到最多50%的情况下,即每次运行10000到50000次)会将结果添加到
    输出
    集合中
  • 处理完
    输入
    中的所有项目后,另一个例程获取
    输出
    ,并对其进行处理

    我需要线程池,以便尽可能快地处理
    输入。
    输入
    的每一个元素都应精确处理一次

    处理元素的顺序是不相关的(对于
    输入
    输出
    )<代码>输出
    是只写的-工作人员将只在那里写,不会对
    输出
    执行任何其他操作

    问题有两个部分,其中线程安全非常重要:

  • 工作线程需要确保当工作线程A处理
    输入的某个元素时,其他工作线程会注意到它,而不会处理同一元素
  • 工作人员完成元素处理后,应将结果添加到
    输出
    集合中
  • 问题:

  • 我可以安全地使用哪种收集类型进行
    input
    collection(?)
  • 对于
    输出
    集合,我是否可以使用普通
    链接列表
    (如果两个线程试图同时向列表中添加不同的对象,是否会出现其中一个对象无法保存的情况)

  • CLQ对于给定约束的输入是合适的,只是在轮询size()检查输入终止时要小心:正如文档中提到的,它不是一个固定时间操作

    对于输出,我怀疑LinkedList是线程安全的,即使只是用于添加。添加意味着改变头部节点的状态,如果两个线程同时添加,则可能会产生问题和分离的元素


    您可以使用另一个CLQ或LinkedBlockingDeque。还有一个更简单的SynchronizedLinkedList。

    您没有提到Java 8,但这是新Java 8并行流库的经典应用程序:

    Collection<Item> input = ... ;
    List<Result> output = input.parallelStream()
        .map(Item::computeResult)
        .filter(Result::matches)
        .collect(Collectors.toList());
    
    集合输入=;
    列表输出=输入。并行流()
    .map(项目::计算机结果)
    .filter(结果::匹配项)
    .collect(Collectors.toList());
    
    结果列表是一个
    ArrayList
    (尽管将来可能会更改)。即使有多个线程在进行处理,这种方法仍然有效,但是
    ArrayList
    不是线程安全的。这是怎么回事

    它工作的原因是每个线程都将结果插入到自己的包含中间结果的列表实例中。最后,将中间结果合并到单个输出列表中。这避免了在多个线程同时将结果写入输出列表时可能发生的潜在争用

    这里使用的原理是螺纹约束(Goetz,第3.3节)。在多线程环境中使用非线程安全的数据结构是安全的,只要一次只有一个线程可以访问它,并且数据在线程之间安全地传递

    如果您不在Java8上,那么可以使用Java7中引入的fork-join框架(请参阅),使用一些相同的多线程技术。它不像Java8流那样方便。(事实上,Java8流是在Fork/Join框架之上构建的。)当然,您将不得不做更多的工作,并且您将无法获得lambdas的便利。但它确实提供了一种合理方便的方法来构造易于拆分的计算

    关键是构造您的计算,以便块可以表示为一个。通常,递归任务包含对输入数据结构的引用、数组或列表索引的范围以及存储中间结果的位置。通过拆分索引范围,可以很容易地拆分任务(“分叉”)。加入每个分叉任务后,其中间结果可以与此任务的中间结果组合。这是以线程受限的方式完成的(连接操作处理线程之间的正确切换)。此外,合并阶段也并行发生,因为不同线程合并来自计算树不同部分的结果都可以并行进行

    参考资料

    Goetz等人,《Java并发的实践》。版权所有2006培生教育


    莉娅,道格。Java Fork/Join框架。《2000年爪哇大城市ACM会议记录》

    我不会对输出使用
    BlockingQueue
    ,因为没有任何东西表明需要阻塞。此外,同步的
    ArrayList
    LinkedList
    具有更好的性能(尤其是因为您提前知道大小)。虽然确实,因为您知道大小的上限,您可以确保ArrayList的容量,但您可能不想分配50k元素数组(我不知道他的内存限制)。但总的来说,你也可能是对的。目前,我经常使用Codenvy作为IDE,目前他们不支持Java 8。一旦他们支持了,我肯定会改用Java 8。