JV
GO

Java to Go

10 lessons

Progress0%
1Variables & Types2Classes → Structs3Interfaces4Exception Handling → Error Values5Threads → Goroutines6Slices and Collections7Packages and Modules8Testing9Go Standard Library10Context and Cancellation
All Mirror Courses
JV
GO
Threads → Goroutines
MirrorLesson 5 of 10
Lesson 5

Threads → Goroutines

Concurrency

Introduction

In this lesson, you'll learn about threads → goroutines in Go. Coming from Java, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
JV
From Java:

In Java, you're familiar with concurrency.

GO
In Go:

Go has its own approach to concurrency, which we'll explore step by step.

The Go Way

Let's see how Go handles this concept. Here's a typical example:

GO
Go Example
package main

import "sync"

// Goroutine — just 'go func()'
go fetchData() // fire and forget

// Channel to receive result
ch := make(chan string)
go func() {
    ch <- fetchData()
}()
result := <-ch // blocks until value

// Multiple goroutines with WaitGroup
var wg sync.WaitGroup
results := make([]string, 5)
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        results[i] = fetch(i)
    }(i)
}
wg.Wait()

Comparing to Java

Here's how you might have written similar code in Java:

JV
Java (What you know)
import java.util.concurrent.*;

// Thread pool
ExecutorService executor = Executors.newFixedThreadPool(4);

// Submit tasks
Future<String> future = executor.submit(() -> {
    return fetchData();
});

// Wait for result
String result = future.get(); // blocks

// CompletableFuture for async
CompletableFuture<String> cf =
    CompletableFuture.supplyAsync(() -> fetchData())
        .thenApply(s -> "Result: " + s);

executor.shutdown();
Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

GO
In Go:

Go goroutines are much lighter than Java threads (KB vs MB stack)

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

GO
In Go:

Channels replace Java's Future/CompletableFuture for passing results

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

GO
In Go:

sync.WaitGroup replaces executor.awaitTermination or CompletableFuture.allOf

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

GO
In Go:

Go runtime schedules goroutines; Java uses OS threads via thread pools

Step-by-Step Breakdown

1. go vs Thread Pool

The 'go' keyword starts a goroutine. Unlike Java where you manage thread pools, the Go runtime schedules goroutines automatically.

JV
Java
executor.submit(() -> doWork());
GO
Go
go doWork()

2. Channel vs Future

Go channels pass values between goroutines — replacing Java's Future.get() and CompletableFuture patterns.

JV
Java
Future<String> f = executor.submit(...); String r = f.get();
GO
Go
ch := make(chan string)
go func() { ch <- fetchData() }()
result := <-ch

3. WaitGroup

sync.WaitGroup waits for a group of goroutines — like calling join() on all threads or CompletableFuture.allOf().

JV
Java
CompletableFuture.allOf(futures).join();
GO
Go
var wg sync.WaitGroup
wg.Add(n); // for each goroutine: go func() { defer wg.Done(); ... }()
wg.Wait()

Common Mistakes

When coming from Java, developers often make these mistakes:

  • Go goroutines are much lighter than Java threads (KB vs MB stack)
  • Channels replace Java's Future/CompletableFuture for passing results
  • sync.WaitGroup replaces executor.awaitTermination or CompletableFuture.allOf
Common Pitfall
Don't assume Go works exactly like Java. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • go keyword starts lightweight goroutines
  • Channels replace Future/CompletableFuture
  • WaitGroup replaces thread joins or allOf
  • Go runtime manages scheduling; no thread pool needed
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your Java code in Go to practice these concepts.
PreviousNext