Go Concurrency (Roadmap)

Status: To Be Implemented Timeline: Phase 2 (Future)

This section will compare Java multithreading with Go's concurrency model. Use this page to understand when to choose Go vs Java for concurrent applications.


Overview

Go revolutionized concurrency with goroutines and channels, providing a simpler mental model than traditional thread-based concurrency. This section will explore how Go's approach differs and when each is preferable.


Planned Topics

1. Goroutines vs Threads

  • Why Goroutines are Lighter: Green threads, stackful coroutines, scheduler aspects
  • Memory Footprint: Goroutines (~2KB) vs Java platform threads (~1MB) vs Java virtual threads (~100B)
  • Creation Speed: Millions of goroutines vs thousands of platform threads
  • Use Case Comparison: When each model shines

2. Channels vs Queues

  • Channel Semantics: Typed, built-in, syntax sugar
  • BlockingQueue Comparison: More explicit, more control
  • Deadlock Prevention: Go's select vs Java's patterns
  • Performance Trade-offs

3. Go's select vs Java Patterns

  • select Statement: Wait for any of multiple channels
  • Java Equivalents: CompletableFuture, ExecutorService
  • Flow Control: Compositional patterns in both languages

4. When to Pick Go vs Java

Scenario Go Java
High concurrency (100K+ connections) ✅ Goroutines (native) ✅ Virtual threads (Java 21+)
Simple concurrent code ✅ Channels easier ⚠️ More boilerplate
Enterprise ecosystem ❌ Limited ✅ Rich libraries
Existing team Java expertise ❌ New language ✅ Works
System programming ✅ Better fit ❌ JVM overhead
Multi-core CPU semantics ⚠️ Implicit parallelism ✅ Explicit control
Startup time ✅ Fast ❌ JVM startup

5. Code Comparison

Go: Simple Concurrency

// Go: Create 1000 goroutines, channels for results
results := make(chan string, 100)

for i := 0; i < 1000; i++ {
    go func(id int) {
        result := doWork(id)
        results <- result  // Send on channel
    }(i)
}

// Collect results
for i := 0; i < 1000; i++ {
    fmt.Println(<-results)  // Receive from channel
}

Java: Equivalent Pattern

// Java: Thread pool + CompletableFuture
ExecutorService executor = Executors.newFixedThreadPool(100);
List<CompletableFuture<String>> futures = new ArrayList<>();

for (int i = 0; i < 1000; i++) {
    final int id = i;
    futures.add(CompletableFuture.supplyAsync(() -> doWork(id), executor));
}

// Collect results
futures.stream()
    .map(CompletableFuture::join)
    .forEach(System.out::println);

Java 21: Virtual Threads (Closer to Go)

// Java 21: Virtual threads match Go's simplicity
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    List<CompletableFuture<String>> futures = new ArrayList<>();

    for (int i = 0; i < 1000; i++) {
        final int id = i;
        futures.add(CompletableFuture.supplyAsync(() -> doWork(id), executor));
    }

    futures.stream().map(CompletableFuture::join).forEach(System.out::println);
}

6. Goroutines Deep Dive

  • How goroutines are scheduled (M:N model like Java virtual threads)
  • Stack allocation (stackful vs stackless continuations)
  • When goroutines block (compared to Java's virtual thread mount/unmount)

7. Go's Concurrency Primitives

  • sync.Mutex (similar to Java synchronized)
  • sync.Cond (similar to Java Condition)
  • sync.WaitGroup (similar to CountDownLatch)
  • context package (similar to ScopedValue, but hierarchical)

8. Async/Await (Future: Go 1.22+)

  • Go doesn't have built-in async/await (philosophy: goroutines are cheap enough)
  • Pattern: Spawn goroutine instead of await
  • Why this works: Goroutine overhead is negligible

9. Performance Benchmarks

  • 100K concurrent I/O operations: Go vs Java (platform threads) vs Java (virtual threads)
  • Throughput: Requests per second
  • Latency: p50, p99, p99.9
  • Memory: Heap usage, GC implications

10. When Java Wins

Area Why Java Wins
Ecosystem Spring Boot, Quarkus, Kafka clients, endless libraries
IDE Support IntelliJ IDEA, VS Code, Eclipse mature
Static typesafety Robust compile-time checking
JVM optimizations HotSpot, JIT, years of optimization
Debugging tools Flight Recorder, jcmd, thread dumps
Team skills Most teams know Java better

11. When Go Wins

Area Why Go Wins
Simplicity Less boilerplate for concurrency
Startup Binary startup <100ms vs JVM startup
Resource constraint Embedded, edge, containers
Systems code Direct OS integration, no GC pauses
DevOps tooling kubectl, prometheus, container native
Goroutines feel natural Fewer coordination patterns to learn

Conclusion Preview

With Java 21+ virtual threads:

  • Java is now competitive with Go for high-concurrency services
  • Familiar ecosystem + simple concurrency model + graceful shutdown
  • Trade-off: JVM startup time, memory baseline, GC pauses

For new projects:

  • I/O-bound services at scale: Java 21+ with virtual threads or Go
  • Existing Java teams: Upgrade to Java 21, use virtual threads
  • Performance-critical systems: Evaluate both; benchmark your workload
  • Embedded/edge: Go likely better (binary size, startup)

To Be Written

  • [ ] Detailed goroutines internals
  • [ ] Channel implementations and semantics
  • [ ] Performance benchmarks with real code
  • [ ] Migration guide: Java service → Go (and vice versa)
  • [ ] Case studies: When each won
  • [ ] Community insights: Go vs Java debates resolved

Resources (As Examples)


Status: This section is a roadmap for future development. Contributions welcome!