Coroutines are usually cooperatively scheduled (that's what the `co-` is for); these are pre-emptively scheduled, first by assignment to a pool of OS threads, and secondly by the OS' own thread scheduler. "Thread" is common nomenclature for pre-emptively scheduled tasks.
"Virtual" is a little less standard, but it draws on existing patterns: they've virtualized threads in the same way that the OS virtualizes the CPU (timeslicing) and virtualizes memory (literally, virtual memory).
They are not fully preemptively scheduled though right? If I have a virtual thread that enters an infinite loop it will not be possible to reclaim its host OS thread no?
That's a good question. It's not very easy to do that with regular Java threads either, though [0], and I think everybody considers those "fully preemptively scheduled".
Preemptive scheduling is more about whether the scheduler (in this case, the OS scheduling the carrier threads) can pause a thread no matter where it is in its processing, and since virtual threads are executed by OS threads (the virtual part is just the JVM tracking the context and where to resume at), they're preemptive.
Hmm, not sure I agree. In the case of OS threads, the kernel will preempt a misbehaving thread and give the CPU to another thread according to priority. In the case where a virtual thread enters an infinite loop however there is no way for the virtual thread scheduler to do the same, unless kernel interruptions of the stuck host OS thread somehow return control to the virtual thread scheduler instead of whatever code was executing when the host thread was preempted. It's not clear to me this is really feasible though.
Yes, it's definitely possible that a spinning virtual thread will effectively pin the current OS thread. The Loom folks could keep, say, a count of how many instructions the virtual thread has executed, and pre-empt it itself if it needs to. This could fight a little with the OS scheduler, so I'm not sure what the tradeoffs are, but if you absolutely cannot allow a spinning virtual thread to effectively pin an OS thread, you'd want to do this.
If you're going to do a bunch of computation without blocking, I'm not sure virtual threads are the tool you want to apply in the first place. They're meant to provide cheap blocking and cheap context switching. If you've got a job that's more CPU-bound than I/O bound, it's probably worth using OS threads instead.
"Virtual" is a little less standard, but it draws on existing patterns: they've virtualized threads in the same way that the OS virtualizes the CPU (timeslicing) and virtualizes memory (literally, virtual memory).