diff --git a/emper/Dispatcher.hpp b/emper/Dispatcher.hpp
index 4aca48c416e84ec37313986723ae880201e5e88c..9b2d390ee9b297d3770e26c52bee4dd1142f90ac 100644
--- a/emper/Dispatcher.hpp
+++ b/emper/Dispatcher.hpp
@@ -57,4 +57,5 @@ class Dispatcher : public Logger<LogSubsystem::DISP> {
 	static auto isDispatchedControlFlow() -> bool { return getCurrentFiberPtr() != nullptr; }
 
 	friend ContextManager;
+	friend class Scheduler;
 };
diff --git a/emper/Fiber.hpp b/emper/Fiber.hpp
index 7caf6080b50f17aa05747465529f03e829356992..9f6965f9e2526c26e637bdb9fb2e378ac54e3e61 100644
--- a/emper/Fiber.hpp
+++ b/emper/Fiber.hpp
@@ -112,6 +112,8 @@ class ALIGN_TO_CACHE_LINE Fiber : public Logger<LogSubsystem::F> {
 
 	void print() const;
 
+	[[nodiscard]] auto isRunnable() const -> bool { return runnable; }
+
 	friend auto operator<<(std::ostream& strm, const Fiber& fiber) -> std::ostream&;
 
 	static inline auto from(fiber_fun_t function, void* arg) -> Fiber* {
diff --git a/emper/RuntimeStrategy.hpp b/emper/RuntimeStrategy.hpp
index 2cbe48bdc9a1a49f9a680dcadfdce0c4f52da49f..6fc7723517701bb166568802d95390703be213d1 100644
--- a/emper/RuntimeStrategy.hpp
+++ b/emper/RuntimeStrategy.hpp
@@ -11,6 +11,7 @@ class RuntimeStrategyStats;
 
 class RuntimeStrategy {
 	friend class Runtime;
+	friend class Scheduler;
 
  private:
 	virtual auto getScheduler() -> Scheduler& = 0;
diff --git a/emper/Scheduler.cpp b/emper/Scheduler.cpp
index eb4dde0b187e9d719b8ca1c412affbecc2fcc1bf..534edfbe8dac6d4eb4b5da096bedcc7232bef845 100644
--- a/emper/Scheduler.cpp
+++ b/emper/Scheduler.cpp
@@ -4,8 +4,10 @@
 
 #include "CallerEnvironment.hpp"
 #include "Runtime.hpp"
+#include "RuntimeStrategy.hpp"
 
-Scheduler::Scheduler(Runtime& runtime) : runtime(runtime) {}
+Scheduler::Scheduler(Runtime& runtime, RuntimeStrategy& strategy)
+		: runtime(runtime), dispatcher(strategy.getDispatcher()) {}
 
 void Scheduler::addNewWorkerHook(const std::function<void(workerid_t)>& hook) {
 	runtime.addNewWorkerHook(hook);
diff --git a/emper/Scheduler.hpp b/emper/Scheduler.hpp
index d71ba18b813d1be89113d6bff27520315366b1aa..bb1d34bfed6dbf92d228c75265ec0c25ff986788 100644
--- a/emper/Scheduler.hpp
+++ b/emper/Scheduler.hpp
@@ -7,12 +7,14 @@
 
 #include "CallerEnvironment.hpp"
 #include "Debug.hpp"	// for LogSubsystem, LogSubsystem::SCHED, Logger
+#include "Dispatcher.hpp"
 #include "Emper.hpp"
 #include "Fiber.hpp"			 // for Fiber
 #include "emper-common.h"	 // for workeraffinity_t
 #include "lib/adt/LockedUnboundedQueue.hpp"
 
 class Runtime;
+class RuntimeStrategy;
 struct NextFiberResult;
 
 class Scheduler : public Logger<LogSubsystem::SCHED> {
@@ -24,7 +26,9 @@ class Scheduler : public Logger<LogSubsystem::SCHED> {
 
  protected:
 	Runtime& runtime;
-	Scheduler(Runtime& runtime);
+	Dispatcher& dispatcher;
+
+	Scheduler(Runtime& runtime, RuntimeStrategy& strategy);
 
 	virtual ~Scheduler() = default;
 
@@ -55,6 +59,8 @@ class Scheduler : public Logger<LogSubsystem::SCHED> {
 	virtual void scheduleFromAnywhereInternal(Fiber& fiber) = 0;
 	virtual void scheduleFromAnywhereInternal(Fiber** fibers, unsigned count) = 0;
 
+	void recycle(Fiber* fiber) { dispatcher.recycle(fiber); };
+
  public:
 	void schedule(Fiber& fiber) {
 		LOGD("Scheduling fiber " << &fiber);
diff --git a/emper/strategies/AbstractWorkStealingScheduler.cpp b/emper/strategies/AbstractWorkStealingScheduler.cpp
index 7ca3722796e8608d64b33f41a2bbd59ce4457c32..62ecb93cc08a6dd3512a68181f2de127adc57c5f 100644
--- a/emper/strategies/AbstractWorkStealingScheduler.cpp
+++ b/emper/strategies/AbstractWorkStealingScheduler.cpp
@@ -7,21 +7,21 @@
 #include "Common.hpp"	 // for unlikely, likely
 #include "Debug.hpp"	 // for ABORT
 #include "Emper.hpp"	 // for OVERFLOW_QUEUE
+#include "Fiber.hpp"
 #include "NextFiberResult.hpp"
 #include "Runtime.hpp"		 // for Runtime
 #include "emper-common.h"	 // for workerid_t
 #include "strategies/AbstractWorkStealingStrategy.hpp"
 #include "strategies/AbstractWorkStealingWorkerStats.hpp"
 
-class Fiber;
-
 using awss = AbstractWorkStealingStrategy;
 
 thread_local AbstractWorkStealingScheduler::WsQueue<AbstractWorkStealingScheduler::QUEUE_SIZE>
 		AbstractWorkStealingScheduler::queue;
 
-AbstractWorkStealingScheduler::AbstractWorkStealingScheduler(Runtime& runtime)
-		: Scheduler(runtime) {
+AbstractWorkStealingScheduler::AbstractWorkStealingScheduler(Runtime& runtime,
+																														 RuntimeStrategy& strategy)
+		: Scheduler(runtime, strategy) {
 	const workerid_t workerCount = runtime.getWorkerCount();
 	queues = new AbstractWorkStealingScheduler::WsQueue<QUEUE_SIZE>*[workerCount];
 
@@ -48,14 +48,24 @@ void AbstractWorkStealingScheduler::scheduleViaWorkStealing(Fiber& fiber) {
 	onNewWork();
 }
 
+auto AbstractWorkStealingScheduler::maybeRecycle(Fiber* fiber) -> bool {
+	if (fiber->isRunnable()) return false;
+
+	recycle(fiber);
+	return true;
+}
+
 auto AbstractWorkStealingScheduler::nextFiberViaWorkStealing() -> std::pair<Fiber*, FiberSource> {
 	FiberSource fiberSource = FiberSource::local;
 	Fiber* fiber;
 
+popBottom:
 	bool poped = queue.popBottom(&fiber);
 	if (likely(poped)) {
 		emper::statsIncr(awss::stats.nextFiberFromLocal);
 
+		if (maybeRecycle(fiber)) goto popBottom;
+
 		goto out;
 	}
 
@@ -70,21 +80,27 @@ auto AbstractWorkStealingScheduler::nextFiberViaWorkStealing() -> std::pair<Fibe
 			// Don't steal from ourselves.
 			if (unlikely(victim == myWorkerId)) continue;
 
+		popTop:
 			poped = queues[victim]->popTop(&fiber);
 			if (poped) {
 				emper::statsIncr(awss::stats.nextFiberStolen);
 
+				if (maybeRecycle(fiber)) goto popTop;
+
 				fiberSource = FiberSource::stolen;
 				goto out;
 			}
 		}
 	}
 
+dequeueFromAnywhere:
 	// Try the "scheduled from anywhere" queue to get work as last resort.
 	fiber = dequeueFiberFromAnywhereQueue();
 	if (fiber) {
 		emper::statsIncr(awss::stats.nextFiberFromAnywhereQueue);
 
+		if (maybeRecycle(fiber)) goto dequeueFromAnywhere;
+
 		fiberSource = FiberSource::anywhereQueue;
 	}
 
diff --git a/emper/strategies/AbstractWorkStealingScheduler.hpp b/emper/strategies/AbstractWorkStealingScheduler.hpp
index 64071b71c28f8572aac2c7165bbd18711f50b5f1..e482243b50e4cbced073810220b028427248afbb 100644
--- a/emper/strategies/AbstractWorkStealingScheduler.hpp
+++ b/emper/strategies/AbstractWorkStealingScheduler.hpp
@@ -17,6 +17,7 @@
 
 class Fiber;
 class Runtime;
+class RuntimeStrategy;
 
 class AbstractWorkStealingScheduler : public Scheduler {
 	template <size_t SIZE>
@@ -41,10 +42,12 @@ class AbstractWorkStealingScheduler : public Scheduler {
 
 	void scheduleViaWorkStealing(Fiber& fiber);
 
+	auto maybeRecycle(Fiber* fiber) -> bool;
+
 	auto nextFiberViaWorkStealing() -> std::pair<Fiber*, FiberSource>;
 
 	auto nextFiberResultViaWorkStealing() -> NextFiberResult;
 
  public:
-	AbstractWorkStealingScheduler(Runtime& runtime);
+	AbstractWorkStealingScheduler(Runtime& runtime, RuntimeStrategy& strategy);
 };
diff --git a/emper/strategies/laws/LawsScheduler.cpp b/emper/strategies/laws/LawsScheduler.cpp
index 138d9ef47a7f6c3016e44a02781bcbab66def4dc..8066c5cb03c5a3efb05ac8ab43efefcb7f4e5dd9 100644
--- a/emper/strategies/laws/LawsScheduler.cpp
+++ b/emper/strategies/laws/LawsScheduler.cpp
@@ -14,7 +14,8 @@
 
 thread_local LawsScheduler::LawsMpscQueue LawsScheduler::priorityQueue;
 
-LawsScheduler::LawsScheduler(Runtime& runtime) : AbstractWorkStealingScheduler(runtime) {
+LawsScheduler::LawsScheduler(Runtime& runtime, RuntimeStrategy& strategy)
+		: AbstractWorkStealingScheduler(runtime, strategy) {
 	const workerid_t workerCount = runtime.getWorkerCount();
 	priorityQueues = new LawsScheduler::LawsMpscQueue*[workerCount];
 
diff --git a/emper/strategies/laws/LawsScheduler.hpp b/emper/strategies/laws/LawsScheduler.hpp
index 8f9c168288c1029435ccd936e7b4cc392f0b40a7..f4b0f242418e48ae92825736456979666913a6c5 100644
--- a/emper/strategies/laws/LawsScheduler.hpp
+++ b/emper/strategies/laws/LawsScheduler.hpp
@@ -8,6 +8,7 @@
 #include "strategies/AbstractWorkStealingScheduler.hpp"
 
 class Runtime;
+class RuntimeStrategy;
 struct NextFiberResult;
 
 class LawsScheduler : public AbstractWorkStealingScheduler {
@@ -27,7 +28,7 @@ class LawsScheduler : public AbstractWorkStealingScheduler {
 	void scheduleFromAnywhereInternal(Fiber** fibers, unsigned count) override;
 
  public:
-	LawsScheduler(Runtime& runtime);
+	LawsScheduler(Runtime& runtime, RuntimeStrategy& strategy);
 
 	auto nextFiber() -> NextFiberResult override;
 };
diff --git a/emper/strategies/laws/LawsStrategy.cpp b/emper/strategies/laws/LawsStrategy.cpp
index 57116344cd124bab6f6a48d604cc7f97aacc6683..603391b469f8b1273dafccf0142dc37b1670c4b6 100644
--- a/emper/strategies/laws/LawsStrategy.cpp
+++ b/emper/strategies/laws/LawsStrategy.cpp
@@ -13,7 +13,7 @@ thread_local LawsWorkerStats LawsStrategy::stats;
 
 LawsStrategy::LawsStrategy(Runtime& runtime)
 		: AbstractWorkStealingStrategy(runtime),
-			scheduler(runtime),
+			scheduler(runtime, *this),
 			dispatcher(runtime),
 			allWorkerStats([] { return &stats; }, runtime) {}
 
diff --git a/emper/strategies/ws/WsScheduler.cpp b/emper/strategies/ws/WsScheduler.cpp
index b57510cb6ec60bc7704a4c86d792d6e23c904a2d..ae98ce217b45cfafff75f2397bf0da215c976a1d 100644
--- a/emper/strategies/ws/WsScheduler.cpp
+++ b/emper/strategies/ws/WsScheduler.cpp
@@ -2,4 +2,5 @@
 // Copyright © 2020-2021 Florian Schmaus
 #include "WsScheduler.hpp"
 
-WsScheduler::WsScheduler(Runtime& runtime) : AbstractWorkStealingScheduler(runtime) {}
+WsScheduler::WsScheduler(Runtime& runtime, RuntimeStrategy& strategy)
+		: AbstractWorkStealingScheduler(runtime, strategy) {}
diff --git a/emper/strategies/ws/WsScheduler.hpp b/emper/strategies/ws/WsScheduler.hpp
index c122f301a6cc817a9fe567154bde5b8ac7ca1707..c0ce9c3b8766f7b673e71a34f04ac24974e1e27c 100644
--- a/emper/strategies/ws/WsScheduler.hpp
+++ b/emper/strategies/ws/WsScheduler.hpp
@@ -8,6 +8,7 @@
 
 class Fiber;
 class Runtime;
+class RuntimeStrategy;
 
 class WsScheduler : public AbstractWorkStealingScheduler {
  protected:
@@ -23,7 +24,7 @@ class WsScheduler : public AbstractWorkStealingScheduler {
 	}
 
  public:
-	WsScheduler(Runtime& runtime);
+	WsScheduler(Runtime& runtime, RuntimeStrategy& strategy);
 
 	auto nextFiber() -> NextFiberResult override { return nextFiberResultViaWorkStealing(); };
 };
diff --git a/emper/strategies/ws/WsStrategy.cpp b/emper/strategies/ws/WsStrategy.cpp
index 11fcd3d02223f41f793f0703dfc8c8f7822596a4..b6eb19e0c03ed9b2821ee7b68eeda6d9f1d1b36d 100644
--- a/emper/strategies/ws/WsStrategy.cpp
+++ b/emper/strategies/ws/WsStrategy.cpp
@@ -10,7 +10,7 @@ class Runtime;
 class RuntimeStrategyStats;
 
 WsStrategy::WsStrategy(Runtime& runtime)
-		: AbstractWorkStealingStrategy(runtime), scheduler(runtime), dispatcher(runtime) {}
+		: AbstractWorkStealingStrategy(runtime), scheduler(runtime, *this), dispatcher(runtime) {}
 
 auto WsStrategy::getScheduler() -> WsScheduler& { return scheduler; }