That's all sequential code, it would be run inside a single "virtual thread". Note that the async code on the right is also sequential, just structured through an async API.
// client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
// .thenApply(HttpResponse::body)
var body = response.body();
// .thenApply(this::getImageURLs)
var urls = getImageURLs(body);
// .thenCompose(this::getImages)
var images = getImages(urls);
// .thenAccept(this::saveImages)
saveImages(images);
And if it had been written this way it would have been clearer that they are, in fact, equivalent. But generally people don't write like this, they use looping constructs.Regardless, the important bit is that the parallel/concurrent bit of the async one is that it is cast off into an async system. The following execution steps are, well, steps. Each executed in sequence. Just like the body of the virtual thread example would be executed, but without the cumbersome noise of thenApply and thenCompose and such.