diff --git a/alarmclock.cabal b/alarmclock.cabal
--- a/alarmclock.cabal
+++ b/alarmclock.cabal
@@ -1,5 +1,5 @@
 name:                alarmclock
-version:             0.4.0.1
+version:             0.4.0.2
 synopsis:            Wake up and perform an action at a certain time.
 description:         Wake up and perform an action at a certain time.
 homepage:            https://bitbucket.org/davecturner/alarmclock
@@ -17,6 +17,7 @@
   build-depends:
       base >=4.8 && <4.10
     , stm
+    , async
     , time
     , clock
     , unbounded-delays
diff --git a/src/Control/Concurrent/AlarmClock.hs b/src/Control/Concurrent/AlarmClock.hs
--- a/src/Control/Concurrent/AlarmClock.hs
+++ b/src/Control/Concurrent/AlarmClock.hs
@@ -35,14 +35,13 @@
   , MonotonicTime(..)
   ) where
 
-import           Control.Concurrent         (forkIO, newEmptyMVar, putMVar,
-                                             readMVar)
+import           Control.Concurrent.Async   (async, wait)
 import           Control.Concurrent.STM     (STM, TVar, atomically, modifyTVar',
-                                             newTVar, readTVar, retry,
+                                             newTVarIO, readTVar, retry,
                                              writeTVar)
 import           Control.Concurrent.Timeout (timeout)
-import           Control.Exception          (bracket, finally)
-import           Control.Monad              (void)
+import           Control.Exception          (bracket)
+import           Control.Monad.Fix          (mfix)
 import           Data.Time                  (UTCTime, diffUTCTime,
                                              getCurrentTime)
 import           GHC.Conc                   (labelThread, myThreadId)
@@ -97,11 +96,9 @@
     -- Note that `setAlarm` must be called once the alarm has gone off to cause
     -- it to go off again.
   -> IO (AlarmClock t)
-newAlarmClock' onWakeUp = do
-  joinVar <- newEmptyMVar
-  ac <- atomically $ AlarmClock (readMVar joinVar) <$> newTVar AlarmNotSet <*> newTVar False
-  void $ forkIO $ runAlarmClock ac (onWakeUp ac) `finally` putMVar joinVar ()
-  return ac
+newAlarmClock' onWakeUp = mfix $ \ac -> do
+  acAsync <- async $ runAlarmClock ac (onWakeUp ac)
+  AlarmClock (wait acAsync) <$> newTVarIO AlarmNotSet <*> newTVarIO False
 
 {-| Destroy the 'AlarmClock' so no further alarms will occur. If the alarm is currently going off
 then this will block until the action is finished. -}
