Very simple - in Java, almost any IO operation in blocking. Exceptions are the stuff in the NIO package, thread interruption and signalling, and maybe process termination.
Well, JS is paired with a single-threaded execution model, so you only have concurrency to worry about. C#, Java has proper multithreading as well, that gives another dimension to the problem.
Then you don’t start it in a virtual thread. Your calls automatically become blocking or not blocking depending on your callsites, which is the proper place to decide that.
Also, as mentioned by another commenter below - is a file exists operation async? Sync? Why, why not?