Modernize dependencies
diff --git a/Cargo.toml b/Cargo.toml
index 2db902e..fb3c127 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,9 @@
 std = []
 
 [dev-dependencies]
+atomic-waker = "1.0.0"
+concurrent-queue = "1.2.2"
 crossbeam = "0.7.3"
-futures = "0.3.4"
-lazy_static = "1.4.0"
+easy-parallel = "3.1.0"
+futures-lite = "1.7.0"
+once_cell = "1.4.1"
diff --git a/examples/panic-propagation.rs b/examples/panic-propagation.rs
index 8d9be39..6dd6128 100644
--- a/examples/panic-propagation.rs
+++ b/examples/panic-propagation.rs
@@ -8,9 +8,8 @@
 
 use async_task::Task;
 use crossbeam::channel::{unbounded, Sender};
-use futures::executor;
-use futures::future::FutureExt;
-use lazy_static::lazy_static;
+use futures_lite::{future, FutureExt};
+use once_cell::sync::Lazy;
 
 /// Spawns a future on the executor.
 fn spawn<F, R>(future: F) -> JoinHandle<R>
@@ -18,22 +17,20 @@
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
-    lazy_static! {
-        // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<Task> = {
-            let (sender, receiver) = unbounded::<Task>();
+    // A channel that holds scheduled tasks.
+    static QUEUE: Lazy<Sender<Task>> = Lazy::new(|| {
+        let (sender, receiver) = unbounded::<Task>();
 
-            // Start the executor thread.
-            thread::spawn(|| {
-                for task in receiver {
-                    // No need for `catch_unwind()` here because panics are already caught.
-                    task.run();
-                }
-            });
+        // Start the executor thread.
+        thread::spawn(|| {
+            for task in receiver {
+                // No need for `catch_unwind()` here because panics are already caught.
+                task.run();
+            }
+        });
 
-            sender
-        };
-    }
+        sender
+    });
 
     // Create a future that catches panics within itself.
     let future = AssertUnwindSafe(future).catch_unwind();
@@ -70,5 +67,5 @@
     let handle = spawn(async {
         panic!("Ooops!");
     });
-    executor::block_on(handle);
+    future::block_on(handle);
 }
diff --git a/examples/panic-result.rs b/examples/panic-result.rs
index 10da772..09f73b8 100644
--- a/examples/panic-result.rs
+++ b/examples/panic-result.rs
@@ -6,9 +6,8 @@
 
 use async_task::{JoinHandle, Task};
 use crossbeam::channel::{unbounded, Sender};
-use futures::executor;
-use futures::future::FutureExt;
-use lazy_static::lazy_static;
+use futures_lite::{future, FutureExt};
+use once_cell::sync::Lazy;
 
 /// Spawns a future on the executor.
 fn spawn<F, R>(future: F) -> JoinHandle<thread::Result<R>>
@@ -16,22 +15,20 @@
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
-    lazy_static! {
-        // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<Task> = {
-            let (sender, receiver) = unbounded::<Task>();
+    // A channel that holds scheduled tasks.
+    static QUEUE: Lazy<Sender<Task>> = Lazy::new(|| {
+        let (sender, receiver) = unbounded::<Task>();
 
-            // Start the executor thread.
-            thread::spawn(|| {
-                for task in receiver {
-                    // No need for `catch_unwind()` here because panics are already caught.
-                    task.run();
-                }
-            });
+        // Start the executor thread.
+        thread::spawn(|| {
+            for task in receiver {
+                // No need for `catch_unwind()` here because panics are already caught.
+                task.run();
+            }
+        });
 
-            sender
-        };
-    }
+        sender
+    });
 
     // Create a future that catches panics within itself.
     let future = AssertUnwindSafe(future).catch_unwind();
@@ -53,7 +50,7 @@
     });
 
     // Block on the future and report its result.
-    match executor::block_on(handle) {
+    match future::block_on(handle) {
         None => println!("The task was canceled."),
         Some(Ok(val)) => println!("The task completed with {:?}", val),
         Some(Err(_)) => println!("The task has panicked"),
@@ -65,7 +62,7 @@
     });
 
     // Block on the future and report its result.
-    match executor::block_on(handle) {
+    match future::block_on(handle) {
         None => println!("The task was canceled."),
         Some(Ok(val)) => println!("The task completed with {:?}", val),
         Some(Err(_)) => println!("The task has panicked"),
diff --git a/examples/spawn-on-thread.rs b/examples/spawn-on-thread.rs
index 5c6bf9b..7545b53 100644
--- a/examples/spawn-on-thread.rs
+++ b/examples/spawn-on-thread.rs
@@ -6,7 +6,7 @@
 
 use async_task::JoinHandle;
 use crossbeam::channel;
-use futures::executor;
+use futures_lite::future;
 
 /// Spawns a future on a new dedicated thread.
 ///
@@ -48,7 +48,7 @@
 
 fn main() {
     // Spawn a future on a dedicated thread.
-    executor::block_on(spawn_on_thread(async {
+    future::block_on(spawn_on_thread(async {
         println!("Hello, world!");
     }));
 }
diff --git a/examples/spawn.rs b/examples/spawn.rs
index 54df1c2..9804939 100644
--- a/examples/spawn.rs
+++ b/examples/spawn.rs
@@ -6,8 +6,8 @@
 
 use async_task::{JoinHandle, Task};
 use crossbeam::channel::{unbounded, Sender};
-use futures::executor;
-use lazy_static::lazy_static;
+use futures_lite::future;
+use once_cell::sync::Lazy;
 
 /// Spawns a future on the executor.
 fn spawn<F, R>(future: F) -> JoinHandle<R>
@@ -15,22 +15,20 @@
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
 {
-    lazy_static! {
-        // A channel that holds scheduled tasks.
-        static ref QUEUE: Sender<Task> = {
-            let (sender, receiver) = unbounded::<Task>();
+    // A channel that holds scheduled tasks.
+    static QUEUE: Lazy<Sender<Task>> = Lazy::new(|| {
+        let (sender, receiver) = unbounded::<Task>();
 
-            // Start the executor thread.
-            thread::spawn(|| {
-                for task in receiver {
-                    // Ignore panics for simplicity.
-                    let _ignore_panic = catch_unwind(|| task.run());
-                }
-            });
+        // Start the executor thread.
+        thread::spawn(|| {
+            for task in receiver {
+                // Ignore panics for simplicity.
+                let _ignore_panic = catch_unwind(|| task.run());
+            }
+        });
 
-            sender
-        };
-    }
+        sender
+    });
 
     // Create a task that is scheduled by sending itself into the channel.
     let schedule = |t| QUEUE.send(t).unwrap();
@@ -47,5 +45,5 @@
     let handle = spawn(async {
         println!("Hello, world!");
     });
-    executor::block_on(handle);
+    future::block_on(handle);
 }
diff --git a/tests/basic.rs b/tests/basic.rs
index 47dd075..5c40fe5 100644
--- a/tests/basic.rs
+++ b/tests/basic.rs
@@ -4,10 +4,8 @@
 use std::task::{Context, Poll};
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
 use crossbeam::channel;
-use futures::future::{self, FutureExt};
-use lazy_static::lazy_static;
+use futures_lite::future;
 
 // Creates a future with event counters.
 //
@@ -18,10 +16,8 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! future {
     ($name:pat, $poll:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Fut(Box<i32>);
@@ -30,14 +26,14 @@
                 type Output = Box<i32>;
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    $poll.fetch_add(1);
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     Poll::Ready(Box::new(0))
                 }
             }
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -55,51 +51,53 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! schedule {
     ($name:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Guard(Box<i32>);
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             move |_task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
             }
         };
     };
 }
 
+fn try_await<T>(f: impl Future<Output = T>) -> Option<T> {
+    future::block_on(future::poll_once(f))
+}
+
 #[test]
 fn drop_and_detach() {
     future!(f, POLL, DROP_F);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     drop(task);
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     handle.detach();
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -109,16 +107,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     handle.detach();
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     drop(task);
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -128,16 +126,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     handle.detach();
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -147,16 +145,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     handle.detach();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -166,16 +164,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     drop(handle);
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -185,16 +183,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     drop(handle);
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -203,29 +201,29 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    assert!((&mut handle).now_or_never().is_none());
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert!(try_await(&mut handle).is_none());
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
-    assert!((&mut handle).now_or_never().is_some());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert!(try_await(&mut handle).is_some());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     drop(handle);
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
diff --git a/tests/join.rs b/tests/join.rs
index ca0ef54..caa39a1 100644
--- a/tests/join.rs
+++ b/tests/join.rs
@@ -1,31 +1,28 @@
 use std::cell::Cell;
 use std::future::Future;
 use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
-use futures::executor::block_on;
-use futures::future;
-use lazy_static::lazy_static;
+use easy_parallel::Parallel;
+use futures_lite::future;
 
 // Creates a future with event counters.
 //
-// Usage: `future!(f, POLL, DROP_F, DROP_O)`
+// Usage: `future!(f, POLL, DROP_F, DROP_T)`
 //
 // The future `f` outputs `Poll::Ready`.
 // When it gets polled, `POLL` is incremented.
 // When it gets dropped, `DROP_F` is incremented.
-// When the output gets dropped, `DROP_O` is incremented.
+// When the output gets dropped, `DROP_T` is incremented.
 macro_rules! future {
-    ($name:pat, $poll:ident, $drop_f:ident, $drop_o:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop_f: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop_o: AtomicCell<usize> = AtomicCell::new(0);
-        }
+    ($name:pat, $poll:ident, $drop_f:ident, $drop_t:ident) => {
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop_f: AtomicUsize = AtomicUsize::new(0);
+        static $drop_t: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Fut(Box<i32>);
@@ -34,14 +31,14 @@
                 type Output = Out;
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    $poll.fetch_add(1);
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     Poll::Ready(Out(Box::new(0)))
                 }
             }
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop_f.fetch_add(1);
+                    $drop_f.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -49,7 +46,7 @@
 
             impl Drop for Out {
                 fn drop(&mut self) {
-                    $drop_o.fetch_add(1);
+                    $drop_t.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -67,17 +64,15 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! schedule {
     ($name:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Guard(Box<i32>);
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -85,7 +80,7 @@
             move |task: Task| {
                 &guard;
                 task.schedule();
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
             }
         };
     };
@@ -97,258 +92,258 @@
 
 #[test]
 fn drop_and_join() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
     drop(task);
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-    assert!(block_on(handle).is_none());
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_O.load(), 0);
+    assert!(future::block_on(handle).is_none());
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 }
 
 #[test]
 fn run_and_join() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-    assert!(block_on(handle).is_some());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_O.load(), 1);
+    assert!(future::block_on(handle).is_some());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 }
 
 #[test]
 fn detach_and_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
     handle.detach();
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
-    assert_eq!(DROP_O.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 }
 
 #[test]
 fn join_twice() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
     task.run();
-    assert_eq!(DROP_O.load(), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-    assert!(block_on(&mut handle).is_some());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_O.load(), 1);
+    assert!(future::block_on(&mut handle).is_some());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 
-    assert!(block_on(&mut handle).is_none());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
-    assert_eq!(DROP_O.load(), 1);
+    assert!(future::block_on(&mut handle).is_none());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 
     handle.detach();
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
 fn join_and_cancel() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             thread::sleep(ms(200));
             drop(task);
 
             thread::sleep(ms(400));
-            assert_eq!(POLL.load(), 0);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_O.load(), 0);
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            assert!(future::block_on(handle).is_none());
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
 
-        assert!(block_on(handle).is_none());
-        assert_eq!(POLL.load(), 0);
-        assert_eq!(SCHEDULE.load(), 0);
-
-        thread::sleep(ms(200));
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_O.load(), 0);
-        assert_eq!(DROP_S.load(), 1);
-    })
-    .unwrap();
+            thread::sleep(ms(200));
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
 fn join_and_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             thread::sleep(ms(400));
 
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
 
             thread::sleep(ms(200));
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            assert!(future::block_on(handle).is_some());
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 
-        assert!(block_on(handle).is_some());
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_O.load(), 1);
-
-        thread::sleep(ms(200));
-        assert_eq!(DROP_S.load(), 1);
-    })
-    .unwrap();
+            thread::sleep(ms(200));
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
 fn try_join_and_run_and_join() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             thread::sleep(ms(400));
 
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
 
             thread::sleep(ms(200));
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            future::block_on(future::or(&mut handle, future::ready(Default::default())));
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-        block_on(future::select(&mut handle, future::ready(())));
-        assert_eq!(POLL.load(), 0);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
+            assert!(future::block_on(handle).is_some());
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 
-        assert!(block_on(handle).is_some());
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_O.load(), 1);
-
-        thread::sleep(ms(200));
-        assert_eq!(DROP_S.load(), 1);
-    })
-    .unwrap();
+            thread::sleep(ms(200));
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
 fn try_join_and_cancel_and_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             thread::sleep(ms(200));
 
             task.run();
-            assert_eq!(POLL.load(), 0);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            future::block_on(future::or(&mut handle, future::ready(Default::default())));
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-        block_on(future::select(&mut handle, future::ready(())));
-        assert_eq!(POLL.load(), 0);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
-
-        drop(handle);
-        assert_eq!(POLL.load(), 0);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
-    })
-    .unwrap();
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
+        })
+        .run();
 }
 
 #[test]
 fn try_join_and_run_and_cancel() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             thread::sleep(ms(200));
 
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 0);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+        })
+        .add(|| {
+            future::block_on(future::or(&mut handle, future::ready(Default::default())));
+            assert_eq!(POLL.load(Ordering::SeqCst), 0);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-        block_on(future::select(&mut handle, future::ready(())));
-        assert_eq!(POLL.load(), 0);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        drop(handle);
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_O.load(), 1);
-    })
-    .unwrap();
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
@@ -372,16 +367,16 @@
     for i in 0..10 {
         let (task, handle) = async_task::spawn(Fut::new(i), drop);
         task.run();
-        assert_eq!(block_on(handle), Some(i));
+        assert_eq!(future::block_on(handle), Some(i));
     }
 
     for i in 0..10 {
         let (task, handle) = async_task::spawn(Fut::new(vec![7; i]), drop);
         task.run();
-        assert_eq!(block_on(handle), Some(vec![7; i]));
+        assert_eq!(future::block_on(handle), Some(vec![7; i]));
     }
 
     let (task, handle) = async_task::spawn(Fut::new("foo".to_string()), drop);
     task.run();
-    assert_eq!(block_on(handle), Some("foo".to_string()));
+    assert_eq!(future::block_on(handle), Some("foo".to_string()));
 }
diff --git a/tests/panic.rs b/tests/panic.rs
index 6641025..0b3ca6a 100644
--- a/tests/panic.rs
+++ b/tests/panic.rs
@@ -1,15 +1,14 @@
 use std::future::Future;
 use std::panic::catch_unwind;
 use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
-use futures::executor::block_on;
-use futures::future;
-use lazy_static::lazy_static;
+use easy_parallel::Parallel;
+use futures_lite::future;
 
 // Creates a future with event counters.
 //
@@ -20,10 +19,8 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! future {
     ($name:pat, $poll:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Fut(Box<i32>);
@@ -32,7 +29,7 @@
                 type Output = ();
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    $poll.fetch_add(1);
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     thread::sleep(ms(400));
                     panic!()
                 }
@@ -40,7 +37,7 @@
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -58,24 +55,22 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! schedule {
     ($name:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Guard(Box<i32>);
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             move |_task: Task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
             }
         };
     };
@@ -91,24 +86,24 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        drop(handle);
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-    })
-    .unwrap();
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -118,16 +113,16 @@
     let (task, handle) = async_task::spawn(f, s);
 
     assert!(catch_unwind(|| task.run()).is_err());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
-    assert!(block_on(handle).is_none());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert!(future::block_on(handle).is_none());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -136,23 +131,23 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    block_on(future::select(&mut handle, future::ready(())));
-    assert_eq!(POLL.load(), 0);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    future::block_on(future::or(&mut handle, future::ready(Default::default())));
+    assert_eq!(POLL.load(Ordering::SeqCst), 0);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     assert!(catch_unwind(|| task.run()).is_err());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
-    assert!(block_on(handle).is_none());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert!(future::block_on(handle).is_none());
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -161,28 +156,28 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
 
             thread::sleep(ms(200));
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            assert!(future::block_on(handle).is_none());
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
 
-        assert!(block_on(handle).is_none());
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-
-        thread::sleep(ms(200));
-        assert_eq!(DROP_S.load(), 1);
-    })
-    .unwrap();
+            thread::sleep(ms(200));
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
@@ -191,25 +186,25 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        block_on(future::select(&mut handle, future::ready(())));
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        drop(handle);
-    })
-    .unwrap();
+            future::block_on(future::or(&mut handle, future::ready(Default::default())));
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            drop(handle);
+        })
+        .run();
 }
 
 #[test]
@@ -218,22 +213,22 @@
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        handle.detach();
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-    })
-    .unwrap();
+            handle.detach();
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+        })
+        .run();
 }
diff --git a/tests/ready.rs b/tests/ready.rs
index 12b3f06..bcf49c0 100644
--- a/tests/ready.rs
+++ b/tests/ready.rs
@@ -1,30 +1,27 @@
 use std::future::Future;
 use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
-use futures::executor::block_on;
-use futures::future;
-use lazy_static::lazy_static;
+use easy_parallel::Parallel;
+use futures_lite::future;
 
 // Creates a future with event counters.
 //
-// Usage: `future!(f, POLL, DROP_F, DROP_O)`
+// Usage: `future!(f, POLL, DROP_F, DROP_T)`
 //
 // The future `f` sleeps for 200 ms and outputs `Poll::Ready`.
 // When it gets polled, `POLL` is incremented.
 // When it gets dropped, `DROP_F` is incremented.
-// When the output gets dropped, `DROP_O` is incremented.
+// When the output gets dropped, `DROP_T` is incremented.
 macro_rules! future {
-    ($name:pat, $poll:ident, $drop_f:ident, $drop_o:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop_f: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop_o: AtomicCell<usize> = AtomicCell::new(0);
-        }
+    ($name:pat, $poll:ident, $drop_f:ident, $drop_t:ident) => {
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop_f: AtomicUsize = AtomicUsize::new(0);
+        static $drop_t: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Fut(Box<i32>);
@@ -33,7 +30,7 @@
                 type Output = Out;
 
                 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    $poll.fetch_add(1);
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     thread::sleep(ms(400));
                     Poll::Ready(Out(Box::new(0)))
                 }
@@ -41,7 +38,7 @@
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop_f.fetch_add(1);
+                    $drop_f.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -49,7 +46,7 @@
 
             impl Drop for Out {
                 fn drop(&mut self) {
-                    $drop_o.fetch_add(1);
+                    $drop_t.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
@@ -67,24 +64,22 @@
 // When it gets dropped, `DROP` is incremented.
 macro_rules! schedule {
     ($name:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let $name = {
             struct Guard(Box<i32>);
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             move |_task: Task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
             }
         };
     };
@@ -96,132 +91,132 @@
 
 #[test]
 fn cancel_during_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_O.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(DROP_O.load(), 1);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
 fn join_during_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
 
             thread::sleep(ms(200));
 
-            assert_eq!(DROP_S.load(), 1);
-        });
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            assert!(future::block_on(handle).is_some());
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
 
-        assert!(block_on(handle).is_some());
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_O.load(), 1);
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        assert_eq!(DROP_S.load(), 1);
-    })
-    .unwrap();
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+        })
+        .run();
 }
 
 #[test]
 fn try_join_during_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, mut handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_O.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        block_on(future::select(&mut handle, future::ready(())));
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
-        drop(handle);
-    })
-    .unwrap();
+            future::block_on(future::or(&mut handle, future::ready(Default::default())));
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
+            drop(handle);
+        })
+        .run();
 }
 
 #[test]
 fn detach_during_run() {
-    future!(f, POLL, DROP_F, DROP_O);
+    future!(f, POLL, DROP_F, DROP_T);
     schedule!(s, SCHEDULE, DROP_S);
     let (task, handle) = async_task::spawn(f, s);
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
-            assert_eq!(POLL.load(), 1);
-            assert_eq!(SCHEDULE.load(), 0);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
-            assert_eq!(DROP_O.load(), 1);
-        });
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 1);
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
-
-        handle.detach();
-        assert_eq!(POLL.load(), 1);
-        assert_eq!(SCHEDULE.load(), 0);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(DROP_O.load(), 0);
-    })
-    .unwrap();
+            handle.detach();
+            assert_eq!(POLL.load(Ordering::SeqCst), 1);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_T.load(Ordering::SeqCst), 0);
+        })
+        .run();
 }
diff --git a/tests/waker_panic.rs b/tests/waker_panic.rs
index 457e69b..3c6c4b3 100644
--- a/tests/waker_panic.rs
+++ b/tests/waker_panic.rs
@@ -2,16 +2,16 @@
 use std::future::Future;
 use std::panic::catch_unwind;
 use std::pin::Pin;
-use std::task::Waker;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
+use atomic_waker::AtomicWaker;
 use crossbeam::channel;
-use futures::future::FutureExt;
-use lazy_static::lazy_static;
+use easy_parallel::Parallel;
+use futures_lite::future;
 
 // Creates a future with event counters.
 //
@@ -25,11 +25,9 @@
 // This waker can be extracted using the `waker` function.
 macro_rules! future {
     ($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-            static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
-        }
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static WAKER: AtomicWaker = AtomicWaker::new();
 
         let ($name, $waker) = {
             struct Fut(Cell<bool>, Box<i32>);
@@ -38,8 +36,8 @@
                 type Output = ();
 
                 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    WAKER.store(Some(cx.waker().clone()));
-                    $poll.fetch_add(1);
+                    WAKER.register(cx.waker());
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     thread::sleep(ms(400));
 
                     if self.0.get() {
@@ -53,13 +51,11 @@
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
-            (Fut(Cell::new(false), Box::new(0)), || {
-                WAKER.swap(None).unwrap()
-            })
+            (Fut(Cell::new(false), Box::new(0)), || WAKER.take().unwrap())
         };
     };
 }
@@ -75,10 +71,8 @@
 // Receiver `chan` extracts the task when it is scheduled.
 macro_rules! schedule {
     ($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let ($name, $chan) = {
             let (s, r) = channel::unbounded();
@@ -87,14 +81,14 @@
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             let sched = move |task: Task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
                 s.send(task).unwrap();
             };
 
@@ -107,6 +101,10 @@
     Duration::from_millis(ms)
 }
 
+fn try_await<T>(f: impl Future<Output = T>) -> Option<T> {
+    future::block_on(future::poll_once(f))
+}
+
 #[test]
 fn wake_during_run() {
     future!(f, waker, POLL, DROP_F);
@@ -118,36 +116,36 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            w.wake();
+            handle.detach();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake();
-        handle.detach();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -161,35 +159,35 @@
     w.wake();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -203,42 +201,42 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            w.wake();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -252,42 +250,42 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             assert!(catch_unwind(|| task.run()).is_err());
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            w.wake();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -298,31 +296,31 @@
 
     task.run();
     waker().wake();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     let mut handle = handle;
-    assert!((&mut handle).now_or_never().is_none());
+    assert!(try_await(&mut handle).is_none());
 
     let task = chan.recv().unwrap();
     assert!(catch_unwind(|| task.run()).is_err());
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
-    assert!((&mut handle).now_or_never().is_some());
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert!(try_await(&mut handle).is_some());
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
 
     drop(waker());
     drop(handle);
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
diff --git a/tests/waker_pending.rs b/tests/waker_pending.rs
index 683e595..e0d5044 100644
--- a/tests/waker_pending.rs
+++ b/tests/waker_pending.rs
@@ -1,14 +1,14 @@
 use std::future::Future;
 use std::pin::Pin;
-use std::task::Waker;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
+use atomic_waker::AtomicWaker;
 use crossbeam::channel;
-use lazy_static::lazy_static;
+use easy_parallel::Parallel;
 
 // Creates a future with event counters.
 //
@@ -22,11 +22,9 @@
 // This waker can be extracted using the `waker` function.
 macro_rules! future {
     ($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-            static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
-        }
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static WAKER: AtomicWaker = AtomicWaker::new();
 
         let ($name, $waker) = {
             struct Fut(Box<i32>);
@@ -35,8 +33,8 @@
                 type Output = ();
 
                 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    WAKER.store(Some(cx.waker().clone()));
-                    $poll.fetch_add(1);
+                    WAKER.register(cx.waker());
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     thread::sleep(ms(400));
                     Poll::Pending
                 }
@@ -44,11 +42,11 @@
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
-            (Fut(Box::new(0)), || WAKER.swap(None).unwrap())
+            (Fut(Box::new(0)), || WAKER.take().unwrap())
         };
     };
 }
@@ -64,10 +62,8 @@
 // Receiver `chan` extracts the task when it is scheduled.
 macro_rules! schedule {
     ($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let ($name, $chan) = {
             let (s, r) = channel::unbounded();
@@ -76,14 +72,14 @@
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             let sched = move |task: Task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
                 s.send(task).unwrap();
             };
 
@@ -107,34 +103,34 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 2);
-            assert_eq!(DROP_F.load(), 0);
-            assert_eq!(DROP_S.load(), 0);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 2);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
             assert_eq!(chan.len(), 1);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            w.wake_by_ref();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake_by_ref();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 2);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 1);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 2);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 1);
+        })
+        .run();
 
     chan.recv().unwrap();
     drop(waker());
@@ -151,35 +147,35 @@
     w.wake();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -193,42 +189,42 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            w.wake();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -242,42 +238,42 @@
     w.wake_by_ref();
     let task = chan.recv().unwrap();
 
-    crossbeam::scope(|scope| {
-        scope.spawn(|_| {
+    Parallel::new()
+        .add(|| {
             task.run();
             drop(waker());
-            assert_eq!(POLL.load(), 2);
-            assert_eq!(SCHEDULE.load(), 1);
-            assert_eq!(DROP_F.load(), 1);
-            assert_eq!(DROP_S.load(), 1);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
             assert_eq!(chan.len(), 0);
-        });
+        })
+        .add(|| {
+            thread::sleep(ms(200));
 
-        thread::sleep(ms(200));
+            drop(handle);
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        drop(handle);
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            w.wake();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
+            assert_eq!(chan.len(), 0);
 
-        w.wake();
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 0);
-        assert_eq!(DROP_S.load(), 0);
-        assert_eq!(chan.len(), 0);
+            thread::sleep(ms(400));
 
-        thread::sleep(ms(400));
-
-        assert_eq!(POLL.load(), 2);
-        assert_eq!(SCHEDULE.load(), 1);
-        assert_eq!(DROP_F.load(), 1);
-        assert_eq!(DROP_S.load(), 1);
-        assert_eq!(chan.len(), 0);
-    })
-    .unwrap();
+            assert_eq!(POLL.load(Ordering::SeqCst), 2);
+            assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+            assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
+            assert_eq!(chan.len(), 0);
+        })
+        .run();
 }
 
 #[test]
@@ -290,24 +286,24 @@
     let w = waker();
 
     handle.detach();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     drop(w);
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -319,24 +315,24 @@
 
     task.run();
     drop(waker());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     drop(handle);
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -348,23 +344,23 @@
 
     task.run();
     drop(waker());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     handle.detach();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 1);
 
     chan.recv().unwrap().run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
diff --git a/tests/waker_ready.rs b/tests/waker_ready.rs
index b97425a..bb7e648 100644
--- a/tests/waker_ready.rs
+++ b/tests/waker_ready.rs
@@ -1,15 +1,14 @@
 use std::cell::Cell;
 use std::future::Future;
 use std::pin::Pin;
-use std::task::Waker;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::task::{Context, Poll};
 use std::thread;
 use std::time::Duration;
 
 use async_task::Task;
-use crossbeam::atomic::AtomicCell;
+use atomic_waker::AtomicWaker;
 use crossbeam::channel;
-use lazy_static::lazy_static;
 
 // Creates a future with event counters.
 //
@@ -23,11 +22,9 @@
 // This waker can be extracted using the `waker` function.
 macro_rules! future {
     ($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-            static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
-        }
+        static $poll: AtomicUsize = AtomicUsize::new(0);
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static WAKER: AtomicWaker = AtomicWaker::new();
 
         let ($name, $waker) = {
             struct Fut(Cell<bool>, Box<i32>);
@@ -36,8 +33,8 @@
                 type Output = Box<i32>;
 
                 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-                    WAKER.store(Some(cx.waker().clone()));
-                    $poll.fetch_add(1);
+                    WAKER.register(cx.waker());
+                    $poll.fetch_add(1, Ordering::SeqCst);
                     thread::sleep(ms(200));
 
                     if self.0.get() {
@@ -51,13 +48,11 @@
 
             impl Drop for Fut {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
-            (Fut(Cell::new(false), Box::new(0)), || {
-                WAKER.swap(None).unwrap()
-            })
+            (Fut(Cell::new(false), Box::new(0)), || WAKER.take().unwrap())
         };
     };
 }
@@ -73,10 +68,8 @@
 // Receiver `chan` extracts the task when it is scheduled.
 macro_rules! schedule {
     ($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
-        lazy_static! {
-            static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
-            static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
-        }
+        static $drop: AtomicUsize = AtomicUsize::new(0);
+        static $sched: AtomicUsize = AtomicUsize::new(0);
 
         let ($name, $chan) = {
             let (s, r) = channel::unbounded();
@@ -85,14 +78,14 @@
 
             impl Drop for Guard {
                 fn drop(&mut self) {
-                    $drop.fetch_add(1);
+                    $drop.fetch_add(1, Ordering::SeqCst);
                 }
             }
 
             let guard = Guard(Box::new(0));
             let sched = move |task: Task| {
                 &guard;
-                $sched.fetch_add(1);
+                $sched.fetch_add(1, Ordering::SeqCst);
                 s.send(task).unwrap();
             };
 
@@ -115,32 +108,32 @@
     assert!(chan.is_empty());
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
     task = chan.recv().unwrap();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -154,32 +147,32 @@
     assert!(chan.is_empty());
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake_by_ref();
     task = chan.recv().unwrap();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     task.run();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake_by_ref();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -191,10 +184,10 @@
     handle.detach();
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     let w2 = waker().clone();
@@ -204,22 +197,22 @@
 
     task = chan.recv().unwrap();
     task.run();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     w3.wake();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     drop(w2);
     drop(waker());
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
 }
 
 #[test]
@@ -230,27 +223,27 @@
     handle.detach();
 
     task.run();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     let w = waker();
 
     w.wake_by_ref();
     drop(chan.recv().unwrap());
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     w.wake();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }
 
@@ -263,24 +256,24 @@
 
     task.run();
     let w = waker();
-    assert_eq!(POLL.load(), 1);
-    assert_eq!(SCHEDULE.load(), 0);
-    assert_eq!(DROP_F.load(), 0);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 1);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 0);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     w.wake();
     chan.recv().unwrap().run();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 0);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 0);
     assert_eq!(chan.len(), 0);
 
     waker().wake();
-    assert_eq!(POLL.load(), 2);
-    assert_eq!(SCHEDULE.load(), 1);
-    assert_eq!(DROP_F.load(), 1);
-    assert_eq!(DROP_S.load(), 1);
+    assert_eq!(POLL.load(Ordering::SeqCst), 2);
+    assert_eq!(SCHEDULE.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_F.load(Ordering::SeqCst), 1);
+    assert_eq!(DROP_S.load(Ordering::SeqCst), 1);
     assert_eq!(chan.len(), 0);
 }