'Green threads' (user-space scheduled threads, cheap to create) keep being reinvented in different languages. Erlang processes in 1986, goroutines in 2009, Java virtual threads in 2023. Each iteration learned from the previous; the pattern has converged on a few key ideas.

Advertisement

Erlang processes — the original

Tiny isolated processes (KBs of memory). Per-process heap (no shared state). Message passing. Preemptive scheduling. Built for telecom: millions of concurrent connections, hot code upgrade. Underpinned the whole BEAM/OTP ecosystem.

Goroutines — Go's bet

Stack starts small (4-8KB), grows as needed. Cooperative scheduling at function calls and channel ops. M:N scheduler (M goroutines on N OS threads). Built for network services; the 'just spawn a goroutine per request' pattern works at million-connection scale.

Advertisement

Virtual threads — Java's catch-up

Java 21+. Pre-existing thread API (java.lang.Thread) but cheap. Each VT is ~8KB. Carrier threads (real OS threads) execute multiple VTs. Goal: 'thread per request' programming model without OS thread cost.

The converged design

Small starting stack. M:N scheduling. Cooperative yield points at I/O. Optional preemption for long CPU-bound runs. The ergonomic 'just spawn one' model. Once-radical ideas now baseline expectations.

What's still different

Erlang: full isolation (one process crash doesn't affect others). Go: shared memory, channels for communication. Java VT: shared memory with no message passing primitive — different model. Each picks a point on the safety/ergonomics curve.

Cheap green threads + M:N scheduling + cooperative yield. Erlang pioneered, Go popularized, Java caught up. Same answer to the same question.