They also make use of constructs that are overkill for such simple examples. For example, the first example could be written as:
Thread.startVirtualThread(() -> say("world"));
say("hello");
which would also replicate same concurrency bug as in the original Go program (the Java example, as written, does not have that bug, but neither would var t = Thread.startVirtualThread(() -> say("world"));
say("hello");
t.join();
).Go makes certain concurrency bugs easy to introduce and hard to find, while Java helps avoid them, but that is also not easy to see from these particular examples.