Аккаунт Войти / Регистрация
Тема
Размер текста
Context, propagation, and cancellation patterns in Go vs Java | Patterns, idioms, and best practices of Go

Context, propagation, and cancellation patterns in Go vs Java | Patterns, idioms, and best practices of Go

1. Context and its role

In Go context.Context is used to pass cancellation signals and timeouts between goroutine, as well as to pass values (propagation). For Java developers, this is somewhat similar to Future with cancellation, Thread.interrupt() and ThreadLocal.


// Go: basic context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

go func(ctx context.Context) {
    select {
    case <-time.After(5 * time.Second):
        fmt.Println("Goroutine completed")
    case <-ctx.Done():
        fmt.Println("Goroutine cancelled:", ctx.Err())
    }
}(ctx)

// Java: cancellation using Future and ExecutorService
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> f = executor.submit(() -> {
    try {
        Thread.sleep(5000);
        System.out.println("Task completed");
    } catch (InterruptedException e) {
        System.out.println("Task cancelled");
    }
});
f.cancel(true); // cancellation
executor.shutdown();
Context helps to pass cancellation signals and timeouts between goroutine, which is especially important in parallel and network tasks.

2. Context propagation

Values can be passed through context so that all child goroutines receive shared information without global variables.


// Go: passing value through context
ctx := context.WithValue(context.Background(), "userID", 42)

go func(ctx context.Context) {
    fmt.Println("UserID:", ctx.Value("userID"))
}(ctx)

// Java: ThreadLocal for context passing
ThreadLocal<Integer> userID = ThreadLocal.withInitial(() -> 42);

Runnable task = () -> System.out.println("UserID: " + userID.get());
new Thread(task).start();
In Go, context propagation simplifies the passing of data and cancellation signals through the goroutine hierarchy instead of global variables or complex parameter passing.

3. Cancellation patterns

The context allows flexible cancellation of tasks. Main approaches:

  • timeout / deadline
  • explicit cancellation through cancel()
  • combination with select for non-blocking wait

// Go: combined example of fan-in with cancellation
func worker(ctx context.Context, jobs <-chan int, results chan<- int) {
    for {
        select {
        case j, ok := <-jobs:
            if !ok { return }
            results <- j * 2
        case <-ctx.Done():
            return
        }
    }
}

ctx, cancel := context.WithCancel(context.Background())
jobs := make(chan int)
results := make(chan int)
go worker(ctx, jobs, results)

// Cancellation
cancel()
Use context for safe cancellation of all related goroutines, especially in fan-in/fan-out schemes.

4. Comparison Table Go vs Java

Concept Go Java Comment
Task Cancellation context with cancel(), timeouts, and deadline Future.cancel(), Thread.interrupt() Go allows safe and centralized cancellation of all child goroutines
Data Passing context.WithValue() passes values through the hierarchy of goroutines ThreadLocal or method parameters In Go, there are fewer global variables, safe in concurrent tasks
Fan-in / Fan-out goroutine + channels + select + context for cancellation ExecutorService + BlockingQueue + Future + manual cancellation Go makes the pattern lighter and more manageable
Timeouts context.WithTimeout / WithDeadline Future.get(timeout), ScheduledExecutor The context provides a single way to set timeouts for the entire chain of goroutines

Summary

The use of context.Context is the key to safe and manageable concurrency in Go. It combines three tasks:

  • Data passing between goroutines (propagation)
  • Task cancellation (cancellation)
  • Timeouts and deadlines

For Java developers, the context is similar to a combination of ThreadLocal + Future/interrupt + timeout. Go provides a more direct, unified, and safe management mechanism, especially in fan-in/fan-out schemes.

Оставить комментарий

Мой канал в социальных сетях
Отправляя email, вы принимаете условия политики конфиденциальности

Полезные статьи:

Multithreading in Go and Java: types of tasks and solution patterns
Multithreading is not just about "starting a million threads and letting them calculate". It is the art of efficiently using CPU and memory resources, safely processing data, and properly distributing…
Go vs Java - comparison of memory models: happens-before, visibility, reorder, synchronization events, write/read barriers
Memory model is a layer between the program and the processor. Modern CPUs aggressively optimize execution: instructions may be reordered, data may be stored in core caches, and operations may be perf…
Java v25: Choosing the Right Multithreading for Any Task
Introduction The Java world is rapidly evolving, and with each version, new tools are emerging for effectively working with multithreading, collections, and asynchrony. Java 25 brings powerful feature…

Новые статьи:

Concurrency is not about “starting many threads”. It’s about agreements between them. Imagine a restaurant kitchen: — cooks (threads / goroutines) — orders (tasks) — and the main question: how do th…
When HashMap starts killing production: the engineering story of ConcurrentHashMap
Imagine a typical production service. 32 CPU hundreds of threads configuration / session / rate limits cache tens of thousands of operations per second And somewhere inside — a regular Map. At first…
Zero Allocation in Java: what it is and why it matters
Zero Allocation — is an approach to writing code in which no unnecessary objects are created in heap memory during runtime. The main idea: fewer objects → less GC → higher stability and performance. …