Index: wp-includes/default-constants.php
===================================================================
--- wp-includes/default-constants.php	(revision 18653)
+++ wp-includes/default-constants.php	(working copy)
@@ -268,6 +268,12 @@
 
 	if ( !defined('WP_POST_REVISIONS') )
 		define('WP_POST_REVISIONS', true);
+
+	/**
+	 * @since 3.3.0
+	 */
+	if ( !defined( 'WP_CRON_LOCK_TIMEOUT' ) )
+		define('WP_CRON_LOCK_TIMEOUT', 60);  // In seconds
 }
 
 /**
Index: wp-includes/cache.php
===================================================================
--- wp-includes/cache.php	(revision 18653)
+++ wp-includes/cache.php	(working copy)
@@ -102,13 +102,14 @@
  *
  * @param int|string $key What the contents in the cache are called
  * @param string $group Where the cache contents are grouped
+ * @param bool $force Whether to force an update of the local cache from the persistent cache (default is false)
  * @return bool|mixed False on failure to retrieve contents or the cache
  *		contents on success
  */
-function wp_cache_get($key, $group = '') {
+function wp_cache_get( $key, $group = '', $force = false ) {
 	global $wp_object_cache;
 
-	return $wp_object_cache->get($key, $group);
+	return $wp_object_cache->get( $key, $group, $force );
 }
 
 /**
@@ -403,10 +404,11 @@
 	 *
 	 * @param int|string $key What the contents in the cache are called
 	 * @param string $group Where the cache contents are grouped
+	 * @param string $force Whether to force a refetch rather than relying on the local cache (default is false)
 	 * @return bool|mixed False on failure to retrieve contents or the cache
 	 *		contents on success
 	 */
-	function get($key, $group = 'default') {
+	function get( $key, $group = 'default', $force = false) {
 		if ( empty ($group) )
 			$group = 'default';
 
Index: wp-includes/cron.php
===================================================================
--- wp-includes/cron.php	(revision 18653)
+++ wp-includes/cron.php	(working copy)
@@ -204,13 +204,13 @@
 	* multiple processes on multiple web servers can run this code concurrently
 	* try to make this as atomic as possible by setting doing_cron switch
 	*/
-	$flag = get_transient('doing_cron');
+	$lock = get_transient('doing_cron');
 
-	if ( $flag > $local_time + 10*60 )
-		$flag = 0;
+	if ( $lock > $local_time + 10*60 )
+		$lock = 0;
 
 	// don't run if another process is currently running it or more than once every 60 sec.
-	if ( $flag + 60 > $local_time )
+	if ( $lock + WP_CRON_LOCK_TIMEOUT > $local_time )
 		return;
 
 	//sanity check
@@ -226,10 +226,11 @@
 		if ( !empty($_POST) || defined('DOING_AJAX') )
 			return;
 
-		set_transient( 'doing_cron', $local_time );
+		$doing_wp_cron = $local_time;
+		set_transient( 'doing_cron', $doing_wp_cron );
 
 		ob_start();
-		wp_redirect( add_query_arg('doing_wp_cron', '', stripslashes($_SERVER['REQUEST_URI'])) );
+		wp_redirect( add_query_arg('doing_wp_cron', $doing_wp_cron, stripslashes($_SERVER['REQUEST_URI'])) );
 		echo ' ';
 
 		// flush any buffers and send the headers
@@ -240,9 +241,10 @@
 		return;
 	}
 
-	set_transient( 'doing_cron', $local_time );
+	$doing_wp_cron = $local_time;
+	set_transient( 'doing_cron', $doing_wp_cron );
 
-	$cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron';
+	$cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron=' . $doing_wp_cron;
 	wp_remote_post( $cron_url, array('timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters('https_local_ssl_verify', true)) );
 }
 
Index: wp-cron.php
===================================================================
--- wp-cron.php	(revision 18653)
+++ wp-cron.php	(working copy)
@@ -26,6 +26,24 @@
 	require_once('./wp-load.php');
 }
 
+// Uncached doing_cron transient fetch
+function _get_cron_lock() {
+	global $_wp_using_ext_object_cache, $wpdb;
+
+	$value = 0;
+	if ( $_wp_using_ext_object_cache ) {
+		// Skip local cache and force refetch of doing_cron transient in case
+		// another processs updated the cache
+		$value = wp_cache_get( 'doing_cron', 'transient', true );
+	} else {
+		$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", '_transient_doing_cron' ) );
+		if ( is_object( $row ) )
+			$value = $row->option_value;
+	}
+
+	return $value;
+}
+
 if ( false === $crons = _get_cron_array() )
 	die();
 
@@ -35,26 +53,52 @@
 if ( isset($keys[0]) && $keys[0] > $local_time )
 	die();
 
-foreach ($crons as $timestamp => $cronhooks) {
+$doing_cron_transient = get_transient( 'doing_cron');
+
+// Use global $doing_wp_cron lock otherwise use the GET lock. If no lock, trying grabbing a new lock.
+if ( empty( $doing_wp_cron ) ) {
+	if ( empty( $_GET[ 'doing_wp_cron' ] ) ) {
+		// Called from external script/job. Try setting a lock.
+		if ( $doing_cron_transient && ( $doing_cron_transient + WP_CRON_LOCK_TIMEOUT > $local_time ) )
+			return;
+		$doing_cron_transient = $doing_wp_cron = time();
+		set_transient( 'doing_cron', $doing_wp_cron );
+	} else {
+		$doing_wp_cron = $_GET[ 'doing_wp_cron' ];
+	}
+}
+
+// Check lock
+if ( $doing_cron_transient != $doing_wp_cron )
+	return;
+
+foreach ( $crons as $timestamp => $cronhooks ) {
 	if ( $timestamp > $local_time )
 		break;
 
-	foreach ($cronhooks as $hook => $keys) {
+	foreach ( $cronhooks as $hook => $keys ) {
 
-		foreach ($keys as $k => $v) {
+		foreach ( $keys as $k => $v ) {
 
 			$schedule = $v['schedule'];
 
-			if ($schedule != false) {
+			if ( $schedule != false ) {
 				$new_args = array($timestamp, $schedule, $hook, $v['args']);
 				call_user_func_array('wp_reschedule_event', $new_args);
 			}
 
-			wp_unschedule_event($timestamp, $hook, $v['args']);
+			wp_unschedule_event( $timestamp, $hook, $v['args'] );
 
- 			do_action_ref_array($hook, $v['args']);
+ 			do_action_ref_array( $hook, $v['args'] );
+
+			// If the hook ran too long and another cron process stole the lock, quit.
+			if ( _get_cron_lock() != $doing_wp_cron )
+				return;
 		}
 	}
 }
 
+if ( _get_cron_lock() == $doing_wp_cron )
+	delete_transient( 'doing_cron' );
+
 die();
