Operating systems typically schedule threads preemptively in order to maximize fairness (i.e., in order to give each thread a chance to run at some point).
Co-routine scheduling, which is handled by the programmer, is usually not preemptive.