Knowledge Guide
HomeConcurrencyConcurrency Foundations

Go vs Java — How Concurrency Works Under the Hood

Same word, two machines

"Thread" means different things in the two runtimes, and that single fact explains most of the practical differences. Java uses 1:1 threading: every java.lang.Thread is one real OS thread the kernel schedules. Go uses M:N: the runtime multiplexes many goroutines (G) onto a small set of OS threads (M) via logical processors (P) — the GMP scheduler.

Go multiplexes many goroutines onto few OS threads via P processors; Java maps each Thread one-to-one onto an OS thread
Go multiplexes many goroutines onto few OS threads via P processors; Java maps each Thread one-to-one onto an OS thread

Why that changes everything

Java ThreadGo goroutine
Mapping1:1 with an OS threadM:N — many per OS thread
Initial stack~512KB–1MB (fixed)~2KB (grows/shrinks on demand)
Created bythe OS (syscall)the Go runtime (cheap)
Context switchkernel, ~1–10 µsuser space, ~tens of ns
Practical maxthousandshundreds of thousands+
SchedulerOS, preemptiveGo runtime, cooperative + async-preemptive (1.14+)
Blocking syscallties up its OS threadruntime parks the G, reuses the M for other Gs

Because a goroutine is ~500× cheaper than a thread, Go's idiom is "just start a goroutine per task." Java's expensive threads are why the ecosystem leans on bounded thread pools (ExecutorService) — you reuse a few OS threads instead of spawning many.

The blocking-I/O difference (the big one)

Block a Java thread on a socket read and that OS thread is stuck doing nothing until data arrives — 10,000 blocked connections need ~10,000 threads. Go's runtime intercepts the blocking call: it hands the network wait to an internal netpoller and frees the OS thread to run other goroutines, so 10,000 connections can be 10,000 goroutines on a handful of threads. This is why Go feels effortless for high-concurrency network servers.

// Go: 100,000 goroutines — fine
for i := 0; i < 100_000; i++ { go handle(i) }

// Java (classic): 100,000 threads — OutOfMemoryError / thrashing
for (int i = 0; i < 100_000; i++) new Thread(() -> handle()).start();  // don't

Java is closing the gap: virtual threads (Project Loom)

JDK 21 added virtual threads — the JVM's own M:N green threads scheduled onto a small carrier pool, with the runtime parking them on blocking I/O. It brings Go's "a thread per request" model to Java: Thread.ofVirtual().start(task) or Executors.newVirtualThreadPerTaskExecutor(). The synchronization tools (locks, atomics) are unchanged — only the scheduling model caught up.

So which, when?

Takeaways


Re-authored for this guide; GMP-vs-1:1 scheduler diagram hand-authored as SVG. Follows the Go runtime scheduler design (Dmitry Vyukov), the Go memory model, and the JEP 444 (Virtual Threads) documentation. See also: Go Concurrency — Goroutines, Channels & CSP; Thread pools & Executors.

🤖 Don't fully get this? Learn it with Claude

Stuck on Go vs Java — How Concurrency Works Under the Hood? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Go vs Java — How Concurrency Works Under the Hood** (Concurrency) and want to truly understand it. Explain Go vs Java — How Concurrency Works Under the Hood from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Go vs Java — How Concurrency Works Under the Hood** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Go vs Java — How Concurrency Works Under the Hood** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Go vs Java — How Concurrency Works Under the Hood** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes