import java.util.ArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

public class MoneyAndCounter {
    record Money(long minor, String currency) {
        Money {
            if (minor < 0 || currency == null || currency.isBlank()) {
                throw new IllegalArgumentException("invalid money");
            }
        }
        Money plus(Money other) {
            if (!currency.equals(other.currency)) {
                throw new IllegalArgumentException("currency mismatch");
            }
            return new Money(Math.addExact(minor, other.minor), currency);
        }
    }
    public static void main(String[] args) throws Exception {
        var sum = new Money(1990, "CNY").plus(new Money(2000, "CNY"));
        if (sum.minor() != 3990) throw new IllegalStateException("wrong sum");
        try {
            sum.plus(new Money(1, "USD"));
            throw new IllegalStateException("mismatch accepted");
        } catch (IllegalArgumentException expected) {
            if (!expected.getMessage().equals("currency mismatch")) throw expected;
        }
        var counter = new AtomicInteger();
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            var futures = new ArrayList<Future<?>>();
            for (int i = 0; i < 1000; i++) {
                futures.add(executor.submit(() -> counter.incrementAndGet()));
            }
            for (var future : futures) future.get();
        }
        if (counter.get() != 1000) throw new IllegalStateException("lost update");
        System.out.printf("money=%d %s; counter=%d%n", sum.minor(), sum.currency(), counter.get());
    }
}
