Executor (plain threading): allows you to define multiple threads (a pool of threads) which run atomic units of work in parallel. Depending on resources, max number of threads is limited. If on thread is blocked, it will wait until it can continue. (i.e. we have parallelism but no asynchronicity)
CompleteableFuture: allows the same as above, however now if a thread is blocked it can switch to another task while waiting for the original work to become unblocked. (i.e. now we have parallelism and asynchronicity)
Webflux: allows the same as the above, but where CompleteableFuture is eagerly executed, webflux is designed to be lazily executed (i.e. executed only when required - on subsciption). This allows the design to implement backpressure and control upstream workloads
Executor (plain threading): allows you to define multiple threads (a pool of threads) which run atomic units of work in parallel. Depending on resources, max number of threads is limited. If on thread is blocked, it will wait until it can continue. (i.e. we have parallelism but no asynchronicity)
CompleteableFuture: allows the same as above, however now if a thread is blocked it can switch to another task while waiting for the original work to become unblocked. (i.e. now we have parallelism and asynchronicity)
Webflux: allows the same as the above, but where CompleteableFuture is eagerly executed, webflux is designed to be lazily executed (i.e. executed only when required - on subsciption). This allows the design to implement backpressure and control upstream workloads