Is your goal to be async or non-blocking? If you want to be non-blocking then every method and library you use must also be non-blocking then you never need to dispatch to a separate worker pool and can stay on the IO threads the entire time.
If you want it to be async then you can dispatch to worker threads to handle the blocking operations. A sleep operation is blocking so yes it will block a thread for its duration. That is also true with observables or any of the reactive frameworks.
The defaults for the IO thread and worker thread can be found
here.
IO threads = min (# of CPU cores, 2)
worker threads = IO threads * 8
On a 4 core server, you will have 32 worker threads for blocking operations. You can configure both of these pools to meet your needs. If you dispatch then sleep you will be blocking one of the 32 worker threads but the IO thread is free to accept requests.
Any of the reactive frameworks or WebFlux type frameworks will handle this in the same way unless the underlying libraries are non-blocking. Most JDBC libraries (for now) are all blocking which means the only way to make it async is to run the query in a separate thread blocking that thread until the query returns.