diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+0.3.0
+-----
+* Add `Data.LruCache.IO.Finalizer` for automatically running finalizer
+  when evicting cache entrvies.
+* Rename `newStripedHandle` to `newStripedLruHandle`
+
 0.2.1
 -----
 * Fix build with GHC 7.8
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # lrucaching
 
 [![Build Status](https://travis-ci.org/cocreature/lrucaching.svg?branch=master)](https://travis-ci.org/cocreature/lrucaching)
-[![Hackage](https://img.shields.io/hackage/v/lrucaching.svg?maxAge=2592000)]()
+[![Hackage](https://img.shields.io/hackage/v/lrucaching.svg)](https://hackage.haskell.org/package/lrucaching)
 
 An implementation of lrucaches based on a
 [blogpost](https://jaspervdj.be/posts/2015-02-24-lru-cache.html) by
diff --git a/lrucaching.cabal b/lrucaching.cabal
--- a/lrucaching.cabal
+++ b/lrucaching.cabal
@@ -1,5 +1,5 @@
 name:                  lrucaching
-version:               0.2.1
+version:               0.3.0
 synopsis:              LRU cache
 description:           Please see README.md
 homepage:              https://github.com/cocreature/lrucaching#readme
@@ -19,6 +19,7 @@
   hs-source-dirs:      src
   exposed-modules:     Data.LruCache
                        Data.LruCache.IO
+                       Data.LruCache.IO.Finalizer
                        Data.LruCache.Internal
   build-depends:       base        >= 4.7  && < 5
                      , base-compat >= 0.9  && < 0.10
diff --git a/src/Data/LruCache/IO.hs b/src/Data/LruCache/IO.hs
--- a/src/Data/LruCache/IO.hs
+++ b/src/Data/LruCache/IO.hs
@@ -5,6 +5,8 @@
 License     : BSD3
 Maintainer  : moritz.kiefer@purelyfunctional.org
 Convenience module for the common case of caching results of IO actions.
+See 'Data.LruCache.IO.Finalizer' if you want to run finalizers
+automatically when cache entries are evicted
 -}
 module Data.LruCache.IO
   ( LruHandle(..)
@@ -12,7 +14,7 @@
   , newLruHandle
   , StripedLruHandle(..)
   , stripedCached
-  , newStripedHandle
+  , newStripedLruHandle
   ) where
 
 import           Control.Applicative ((<$>))
@@ -53,8 +55,8 @@
 
 -- | Create a new 'StripedHandle' with the given number of stripes and
 -- the given capacity for each stripe.
-newStripedHandle :: Int -> Int -> IO (StripedLruHandle k v)
-newStripedHandle numStripes capacityPerStripe =
+newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)
+newStripedLruHandle numStripes capacityPerStripe =
   StripedLruHandle <$> Vector.replicateM numStripes (newLruHandle capacityPerStripe)
 
 -- | Striped version of 'cached'.
diff --git a/src/Data/LruCache/IO/Finalizer.hs b/src/Data/LruCache/IO/Finalizer.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/LruCache/IO/Finalizer.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE BangPatterns #-}
+{-|
+Module      : Data.LruCache.IO.Finalizer
+Copyright   : (c) Moritz Kiefer, 2016
+              (c) Jasper Van der Jeugt, 2015
+License     : BSD3
+Maintainer  : moritz.kiefer@purelyfunctional.org
+Convenience module for the common case of caching results of IO actions 
+when finalizers have to be run when cache entries are evicted.
+-}
+module Data.LruCache.IO.Finalizer
+  ( LruHandle(..)
+  , newLruHandle
+  , cached
+  , StripedLruHandle(..)
+  , newStripedLruHandle
+  , stripedCached
+  ) where
+
+import           Control.Applicative ((<$>))
+import           Data.Foldable (traverse_)
+import           Data.Hashable (Hashable, hash)
+import           Data.IORef (IORef, atomicModifyIORef', newIORef)
+import           Data.Tuple (swap)
+import           Data.Vector (Vector)
+import qualified Data.Vector as Vector
+import           Prelude hiding (lookup)
+
+import           Data.LruCache
+
+-- | Store a LRU cache in an 'IORef to be able to conveniently update it.
+newtype LruHandle k v = LruHandle (IORef (LruCache k (v, v -> IO ())))
+
+-- | Create a new LRU cache of the given size.
+newLruHandle :: Int -> IO (LruHandle k v)
+newLruHandle capacity = LruHandle <$> newIORef (empty capacity)
+
+-- | Return the cached result of the action or, in the case of a cache
+-- miss, execute the action and insert it in the cache.
+cached ::
+  (Hashable k, Ord k) =>
+  LruHandle k v ->
+  k ->
+  IO v ->
+  (v -> IO ()) {- ^ finalizer -} ->
+  IO v
+cached (LruHandle ref) k io finalizer =
+  do lookupRes <- atomicModifyIORef' ref $ \c ->
+       case lookup k c of
+         Nothing      -> (c,  Nothing)
+         Just (v, c') -> (c', Just v)
+     case lookupRes of
+       Just (!v,_)  -> return v
+       Nothing      ->
+         do v <- io
+            evicted <- atomicModifyIORef' ref $ \c -> 
+              swap (insertView k (v,finalizer) c)
+            traverse_ (\(_,(v',finalize')) -> finalize' v') evicted
+            return v
+
+-- | Using a stripe of multiple handles can improve the performance in
+-- the case of concurrent accesses since several handles can be
+-- accessed in parallel.
+newtype StripedLruHandle k v = StripedLruHandle (Vector (LruHandle k v))
+
+-- | Create a new 'StripedHandle' with the given number of stripes and
+-- the given capacity for each stripe.
+newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)
+newStripedLruHandle numStripes capacityPerStripe =
+  StripedLruHandle <$> Vector.replicateM numStripes (newLruHandle capacityPerStripe)
+
+-- | Striped version of 'cached'.
+stripedCached ::
+  (Hashable k, Ord k) =>
+  StripedLruHandle k v ->
+  k ->
+  IO v ->
+  (v -> IO ()) {- ^ finalizer -} ->
+  IO v
+stripedCached (StripedLruHandle v) k =
+    cached (v Vector.! idx) k
+  where
+    idx = hash k `mod` Vector.length v
