# `volatile` is not `std::atomic`

`Appender.write` is called for the same instance from many threads, and the logger never
serialises those calls. Its contract says so outright. So a destination that counts the lines it
took holds shared mutable state, and this is the version that gets written first:

```java
private int written;
public void write(String line) { written++; }
```

200 threads, 1000 lines each, expecting 200000. Measured: `got 121835 (lost 78165)`.

You know why that happens. The interesting part is the fix you reach for next, because Java's
`volatile` is not the C++ keyword you learned to route around. In Java it is specified against the
memory model: a write to it happens-before every later read. So:

```java
private volatile int written;
```

Run it again: `got 51048 (lost 148952)`. Worse on that run, and never correct on any of sixteen.
`volatile` orders the load and the store; it never joins them. `written++` is still a load, an add
and a store, and another thread still lands between them.

What `volatile` does cover is one write read by somebody else, with no arithmetic in the middle.
Curveball 01 runs asynchronous destinations on a background thread. A flag telling that thread to
stop is exactly that shape, and nothing else is.

An increment is a read-modify-write, so it needs one operation that does all three:

```java
private final AtomicInteger written = new AtomicInteger();
written.incrementAndGet();
```

`got 200000 (lost 0)`. That is `fetch_add`, the same instruction you already know, with no lock.
`volatile` qualifies a field. `Atomic*` gives you an operation.
