diff --git a/includes/cache.inc b/includes/cache.inc
index fcf3e5e..6bb537e 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -474,6 +474,10 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
       return FALSE;
     }
 
+    if ($this->hasExpired($cache)) {
+      return FALSE;
+    }
+
     if ($cache->serialized) {
       $cache->data = unserialize($cache->data);
     }
@@ -482,6 +486,7 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
   }
 
   function set($cid, $data, $expire = CACHE_PERMANENT) {
+    if (empty($cid)) return;
     $fields = array(
       'serialized' => 0,
       'created' => REQUEST_TIME,
@@ -505,6 +510,12 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     catch (Exception $e) {
       // The database may not be available, so we'll ignore cache_set requests.
     }
+    try {
+      lock_release("cache:$this->bin:$cid");
+    }
+    catch (Exception $e) {
+      // Error releasing lock
+    }
   }
 
   function delete($cid) {
@@ -615,4 +626,30 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
       ->fetchField();
     return empty($result);
   }
+
+  /**
+   * Check if object has expired
+   * @fixme Smelly code: Also sets a lock. Doesn't quite fit the name hasExpired().
+   */
+  function hasExpired($cache) {
+    if (empty($cache->cid)) return TRUE;
+
+    if ($cache->expire > 0 && $cache->expire < time()) {
+      try {
+        // Expired
+        if  (lock_acquire("cache:$this->bin:$cache->cid")) {
+          // Got lock, assuming caller will fill cache.
+          return TRUE;
+        }
+        else {
+          // Stale
+          return FALSE;
+        }
+      }
+      catch (Exception $e) {
+        // Couldn't lock
+        return TRUE;
+      }
+    }
+  }
 }
