2709
Java8のSteam APIで[並行リダクション(concurrent
reduction)](http://docs.oracle.com/javase/jp/8/api/java/util/stream/package-
summary.html#ConcurrentReduction)をサポートした自作Collectorを作るとき、Collectorの[combiner関数](http://docs.oracle.com/javase/jp/8/api/java/util/stream/Collector.html#combiner--)が
**呼ばれることはない** と仮定しても良いものでしょうか？

（実効的な意味はない）下記サンプルコードでは、自作Collectorは`CONCURRENT`かつ`UNORDERED`特性を持っており：

  * 並列ストリーム(`parallel()`あり)なら並列リダクション = supplier関数があるスレッド上で1回呼ばれる＋各Workerスレッドから並行にaccumulator関数が呼ばれる
  * 逐次ストリーム(`parallel()`なし)なら単一スレッド上のリダクション = supplier関数＋accumulator関数が単一スレッドから呼ばれる

と期待されるため、いずれのケースでもcombiner関数が使われる事は無いと考えられます。

```

    import java.util.stream.*;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.*;
    
    public class DoesConcReductionCollectorNeedsCombiner {
      static public void main(String[] args) {
        ConcurrentMap<Integer, AtomicInteger> result =
          IntStream.range(1, 10_000_001).boxed()  // Stream<Integer>
            .parallel()  // 並列ストリーム化
            .collect(Collector.of(
              () -> new ConcurrentHashMap<>(),
              (m,v) -> {
                AtomicInteger a = m.putIfAbsent(v % 10, new AtomicInteger(v));
                if (a != null)
                  a.getAndAdd(v);
              },
              (m,n) -> {
                // 並行リダクションなら呼び出されない? = 実装不要?
                // （まじめに実装するなら2つの並行Mapのマージが必要）
                System.out.println("!");
                return null;
              },
              Collector.Characteristics.CONCURRENT,
              Collector.Characteristics.UNORDERED
            ));
        System.out.println("r="+result);
      }
    }
    
```
CC BY-SA 3.0
2014-12-27T13:22:59.823
2703
2014-12-28T00:57:50.440
2014-12-27T13:34:57.037
49
49
question
java java8
並行リダクション用Collectorでcombiner関数の実装は必須？
[java.util.stream (Java Platform SE 8
)](http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-
summary.html)

> _Reduction, concurrency, and ordering_
>
> Suppose, however, that the result container used in this reduction was a
> concurrently modifiable collection -- such as a ConcurrentHashMap. In that
> case, the parallel invocations of the accumulator could actually deposit
> their results concurrently into the same shared result container,
> **eliminating the need for the combiner to merge distinct result
> containers**. This potentially provides a boost to the parallel execution
> performance. We call this a concurrent reduction.  
>  A Collector that supports concurrent reduction is marked with the
> Collector.Characteristics.CONCURRENT characteristic. However, a concurrent
> collection also has a downside. If multiple threads are depositing results
> concurrently into a shared container, the order in which results are
> deposited is non-deterministic. Consequently, a concurrent reduction is only
> possible if ordering is not important for the stream being processed.

上記の様に記載されていますので、仰っしゃるとおりに combiner 関数が呼ばれることはないでしょう。
CC BY-SA 3.0
2014-12-27T16:10:54.390
2709
2014-12-27T16:10:54.390
2020-06-17T08:14:45.997
-1
2703
answer
仮定してもいいです。

並列リダクション(concurrency reduction)を行うと判断するために、 Java8 ランタイムは３条件をみます。Concurrency
reduction が起こった場合は、 combiner が利用されません。このことは [JavaDoc
に記載](http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-
summary.html#package.description)されています。

  * ストリームが parallel であること
  * コレクタが concurrent であること
  * ストリームが unordered か、 コレクタが unordered 特性をもつこと

ただし、悩ましいことがあります。私の回答としては、「 combiner は利用されない、しかし実装しなければならない。」です。API
で期待されている実装の一部を抜くというのは、好ましくないという単純な理由からです。

Java8 の Stream API
の設計思想に「順列と並列でAPIの利用方法が同一であること」があります。ですので、使用されないとあなたが判断できる場合でも、APIの呼び出し手順を満たすために実装しなければならない、という状態になっています。ですので、空の実装にするのではなく、動くコードを書いておくべきだと思います。（当然テスト対象になり得ます・・・gaaah）

サンプルの例のようにプログラムが一画面におさまり、combiner の実装を利用者が認識できる状態なら問題はないでしょうけどね。

参考:

  * [Setting of UNORDERED on concurrent collectors](http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-April/001599.html)
  * [State of the Lambda: Libraries Edition - Background](http://cr.openjdk.java.net/~briangoetz/lambda/lambda-libraries-final.html)
CC BY-SA 3.0
2014-12-28T00:57:50.440
2716
2014-12-28T00:57:50.440
4978
2703
answer