Java's ZGC is multiple generations ahead, and I believe is a fairer tradeoff (overall lower throughput (due to read barriers over write barriers), but guaranteed <1ms pause time due to basically everything happening concurrently)
GC pauses are a necessity exactly for the part that can't be done in parallel, and Go is definitely not using ZGC's next-generation design that would decouple the pause's length from the heap size, so we still have our "arbitrary long pause" problem on the table.
>The Go GC avoids making the length of any global application pauses proportional to the size of the heap, and that the core tracing algorithm is performed while the application is actively executing.
>Brief stop-the-world pauses when the GC transitions between the mark and sweep phases.
I didn't benchmark it myself, though. Go is mostly used in stateless microservices where huge heap sizes are very uncommon. We usually scale horizontally, not vertically. Also, Go has value objects which can be allocated on the stack or embedded inside other objects, so it allocates far less garbage than Java. So practically for me Go's GC has been a non-issue, I barely remember it even exists.
Obviously there is not much to synchronize when there is only a single thread.