Shared Maximum with Compare-and-Set

Problem

n threads each hold one number. All of them try to update one shared 'maximum' value, at the same time. At the end, the shared value must be the biggest of all numbers. Print it. (Use a compare-and-set loop, not a lock.)

Constraints

  • 1 <= n <= 20

Examples

Input

4
3 9 2 7

Output

9

Solutions

Best approachTime O(n) expectedSpace O(n)

compareAndSet changes the value only if it is still what we read. If another thread won the race, it returns false and we read again. No thread ever blocks, and no update is lost.

Same code works in Java810172125Basic features only, so nothing changes between versions.

JavaScript and TypeScript have no shared-memory threads here, so they follow the same steps in one thread.

/*
 * Problem : Find the shared maximum.
 * Input   : n and the numbers.
 * Output  : The maximum.
 * Approach: Compare-and-set loop
 * Time    : O(n) expected
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static int solve(int[] a) {
        // Step 1: One shared atomic value. It starts at the smallest possible number.
        java.util.concurrent.atomic.AtomicInteger shared = new java.util.concurrent.atomic.AtomicInteger(Integer.MIN_VALUE);
        Thread[] threads = new Thread[a.length];
        for (int i = 0; i < a.length; i++) {
            final int value = a[i];
            threads[i] = new Thread(() -> {
                // Step 2: Read the current value. If ours is not bigger, nothing to do. Otherwise try to swap.
                while (true) {
                    int current = shared.get();
                    if (value <= current || shared.compareAndSet(current, value)) {
                        break;
                    }
                    // Step 3: compareAndSet fails when another thread changed the value first. The loop reads the new value and tries again.
                }
            });
            threads[i].start();
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        return shared.get();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();
        int[] a = new int[size];
        for (int i = 0; i < size; i++) {
            a[i] = scanner.nextInt();
        }
        System.out.println(solve(a));
    }
}
Hints (2)
  1. Why can a plain 'if bigger then set' lose an update?
  2. What does a false from compareAndSet mean?