I just realized the combiner in the example I referenced is actually thread-safe.
StringBuilder is not thread-safe, but it's different from the combine itself
The combiner 's arguments are two StringBuilder but they're just local variables and have nothing to do with concurrency:
(a, b) -> a.append(",").append(b)