In the JVM, threads are just thin wrappers around native OS threads. And native OS threads have a high footprint and creating them/switching between them is not a lightweight task. To overcome this downside the asynchronous NIO in JDK was brought in which returns the thread to the thread pool while the task is waiting. Once the task is over, another thread from the thread pool is picked up to carry on the task.
How does the system know that the task is over? The task could be waiting for a response from an HTTP server. But since the thread has been returned to the thread pool, who interrupts the CPU to notify that the task is done and the work can be continued?