Atomic Counters in Minitab

Here’s the translation of the atomic counters example from Go to Java, formatted in Markdown suitable for Hugo:

In Java, we can use the java.util.concurrent.atomic package for atomic operations. This example demonstrates the use of atomic counters accessed by multiple threads.

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.CountDownLatch;

public class AtomicCounters {
    public static void main(String[] args) throws InterruptedException {
        // We'll use an AtomicLong to represent our (always-positive) counter.
        AtomicLong ops = new AtomicLong();

        // A CountDownLatch will help us wait for all threads to finish their work.
        CountDownLatch latch = new CountDownLatch(50);

        // We'll start 50 threads that each increment the counter exactly 1000 times.
        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                for (int c = 0; c < 1000; c++) {
                    // To atomically increment the counter we use incrementAndGet().
                    ops.incrementAndGet();
                }
                latch.countDown();
            }).start();
        }

        // Wait until all the threads are done.
        latch.await();

        // Here no threads are writing to 'ops', but using get() it's safe to 
        // atomically read a value even while other threads might be updating it.
        System.out.println("ops: " + ops.get());
    }
}

We expect to get exactly 50,000 operations. Had we used a non-atomic integer and incremented it with ops++, we’d likely get a different number, changing between runs, because the threads would interfere with each other. Moreover, we’d get data race conditions.

To run the program:

$ javac AtomicCounters.java
$ java AtomicCounters
ops: 50000

In this Java version:

  1. We use AtomicLong instead of atomic.Uint64. Java doesn’t have an unsigned 64-bit integer type, so we use a signed one.

  2. Instead of sync.WaitGroup, we use CountDownLatch which serves a similar purpose in Java.

  3. We replace goroutines with Java threads.

  4. The Add method is replaced with incrementAndGet().

  5. The Load method is replaced with get().

This example demonstrates how to use atomic operations in Java to safely manage a counter across multiple threads, similar to the original example’s use of goroutines.