diff --git examples.index.php examples.index.php
index 50d479c..d22c5b1 100644
--- examples.index.php
+++ examples.index.php
@@ -5,24 +5,22 @@
  * @file
  * Example modules
  *
- * - @link ajax_example.module How to use AJAX Forms @endlink
- * - @link batch_example.module Using the Batch API @endlink
- * - @link block_example.module How to define blocks @endlink
- * - @link dbtng_example.module Examples of DBTNG database access in Drupal 7 @endlink
- * - @link email_example.module How to send e-mail @endlink
- * - @link field_example.module How to use fields in the new Field API @endlink
- * - @link filter_example.module How to define a content filter @endlink
+ * - @link ajax_example.module Using AJAX forms @endlink
+ * - @link batch_example.module Using the batch API @endlink
+ * - @link block_example.module Defining blocks @endlink
+ * - @link dbtng_example.module Database examples (DBTNG) @endlink
+ * - @link email_example.module Sending e-mail @endlink
+ * - @link field_example.module Defining fields in the field API @endlink
+ * - @link filter_example.module Defining an input filter @endlink
  * - @link form_example.module Form API examples, including multistep forms @endlink
- * - @link js_example.module Javascript examples for Drupal 7 @endlink
- * - @link node_access_example.module Node access example @endlink
+ * - @link js_example.module Javascript examples @endlink
  * - @link nodeapi_example.module Node API demonstrations showing how a separate module can change the behavior of a node @endlink
- * - @link node_example.module How to define content (node) types in Drupal 7, including fields @endlink
- * - @link node_access_example.module How to restrict access to nodes @endlink
- * - @link nodeapi_example.module How to extend existing content types @endlink
- * - @link page_example.module How to define pages @endlink
- * - @link simpletest_example.module Demonstrates how to write tests for Drupal @endlink
- * - @link token_example.module How to use tokens in Drupal 7 @endlink
- * - @link trigger_example.module Implementing triggers and actions in Drupal 7 @endlink
- * - @link vertical_tabs_example.module Using Vertical Tabs in Drupal 7 @endlink
- * - @link xmlrpc_example.module XML-RPC Example @endlink
+ * - @link node_example.module Creating custom node types, with fields @endlink
+ * - @link page_example.module Creating a custom page @endlink
+ * - @link queue_example.module Using the Queue API @endlink
+ * - @link simpletest_example.module Writing tests for Drupal @endlink
+ * - @link token_example.module Using tokens @endlink
+ * - @link trigger_example.module Implementing triggers and actions @endlink
+ * - @link vertical_tabs_example.module Using vertical tabs @endlink
+ * - @link xmlrpc_example.module XML-RPC example @endlink
  */
diff --git queue_example/queue_example.css queue_example/queue_example.css
new file mode 100644
index 0000000..b314028
--- /dev/null
+++ queue_example/queue_example.css
@@ -0,0 +1,5 @@
+/* $Id$ */
+
+.form-item-string-to-add, div.form-item-claim-time { 
+  display: inline;
+}
\ No newline at end of file
diff --git queue_example/queue_example.info queue_example/queue_example.info
new file mode 100644
index 0000000..26514d2
--- /dev/null
+++ queue_example/queue_example.info
@@ -0,0 +1,7 @@
+; $Id$
+name = Queue example
+description = Examples of using the Drupal Queue API.
+package = Example modules
+core = 7.x
+files[] = queue_example.module
+files[] = queue_example.test
diff --git queue_example/queue_example.module queue_example/queue_example.module
new file mode 100644
index 0000000..ca4fb29
--- /dev/null
+++ queue_example/queue_example.module
@@ -0,0 +1,276 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Examples demonstrating the Drupal Queue API.
+ *
+ * The Queue API provides a traditional FIFO (first-in-first-out) queue,
+ * but also provides the concepts of:
+ * - "Creating" a queued item, which means inserting it into a queue.
+ * - "Claiming" a queued item, which essentially means requesting the next item
+ *   from the queue and holding a lock on that item for a specified period of
+ *   time.
+ * - "Releasing" an item, which means giving up a claim but leaving the item in
+ *   the queue.
+ * - "Deleting" an item, which means finally removing it from the queue.
+ *
+ * This example demonstrates only basic queue functionality, and will use the
+ * default queue implementation, which is SystemQueue, managed using
+ * persistent database storage.
+ *
+ * Further resources include the limited @link queue @endlink documentation and
+ * @link http://www.ent.iastate.edu/it/Batch_and_Queue.pdf Batch vs Queue Presentation slides by John VanDyk @endlink
+ * and @link http://sf2010.drupal.org/conference/sessions/batch-vs-queue-api-smackdown session video. @endlink
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function queue_example_menu() {
+  $items = array();
+  $items['queue_example/insert_remove'] = array(
+    'title' => 'Queue Example: Insert and remove',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('queue_example_add_remove_form'),
+    'access callback' => TRUE,
+  );
+
+  return $items;
+}
+
+/**
+ * Provides an interface to add items to the queue, to retrieve (claim)
+ * an item from the head of the queue, and to claim and delete. Also
+ * allows the user to run cron manually, so that claimed items can be
+ * released.
+ */
+function queue_example_add_remove_form($form, &$form_state) {
+  // Simple counter that makes it possible to put auto-incrementing default
+  // string into the string to insert.
+  if (empty($form_state['storage']['insert_counter'])) {
+    $form_state['storage']['insert_counter'] = 1;
+  }
+
+  $queue_name = !empty($form_state['values']['queue_name']) ? $form_state['values']['queue_name'] : 'queue_example_first_queue';
+  $items = queue_example_retrieve_queue($queue_name);
+
+  // Add CSS to make the form a bit denser.
+  $form['#attached']['css'] = array(drupal_get_path('module', 'queue_example') . '/queue_example.css');
+
+  $form['help'] = array(
+    '#type' => 'markup',
+    '#markup' => '<div>' . t('This page is an interface on the Drupal queue API. You can add new items to the queue, "claim" one (retrieve the next item and keep a lock on it), and delete one (remove it from the queue). Note that claims are not expired until cron runs, so there is a special button to run cron to perform any necessary expirations.') . '</div>',
+  );
+
+  $form['queue_name'] = array(
+    '#type' => 'select',
+    '#title' => t('Choose queue'),
+    '#options' => drupal_map_assoc(array('queue_example_first_queue', 'queue_example_second_queue')),
+  );
+  $form['insert_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Insert into queue'),
+  );
+  $form['insert_fieldset']['string_to_add'] = array(
+    '#type' => 'textfield',
+    '#size' => 10,
+    '#value' => t('item @counter', array('@counter' => $form_state['storage']['insert_counter'])),
+  );
+  $form['insert_fieldset']['add_item'] = array(
+    '#type' => 'submit',
+    '#value' => t('Insert into queue'),
+    '#submit' => array('queue_example_add_remove_form_insert'),
+  );
+  $form['claim_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Claim from queue'),
+    '#collapsible' => TRUE,
+  );
+
+  $form['claim_fieldset']['claim_time'] = array(
+    '#type' => 'radios',
+    '#title' => t('Claim time, in seconds'),
+    '#options' => array(0 => t('none'), 5 => t('5 seconds'), 60 => t('60 seconds')),
+    '#description' => t('This time is only valid if cron runs during this time period. You can run cron manually below.'),
+    '#default_value' => !empty($form_state['values']['claim_time']) ? $form_state['values']['claim_time'] : 5,
+  );
+  $form['claim_fieldset']['claim_item'] = array(
+    '#type' => 'submit',
+    '#value' => t('Claim the next item from the queue'),
+    '#submit' => array('queue_example_add_remove_form_claim'),
+  );
+  $form['claim_fieldset']['claim_and_delete_item'] = array(
+    '#type' => 'submit',
+    '#value' => t('Claim the next item and delete it'),
+    '#submit' => array('queue_example_add_remove_form_delete'),
+  );
+  $form['run_cron'] = array(
+    '#type' => 'submit',
+    '#value' => t('Run cron manually (to expire claimed items)'),
+    '#submit' => array('queue_example_add_remove_form_run_cron'),
+  );
+  $form['delete_queue'] = array(
+    '#type' => 'submit',
+    '#value' => t('Delete the queue and items in it'),
+    '#submit' => array('queue_example_add_remove_form_clear_queue'),
+  );
+  $form['status_fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Queue status'),
+    '#collapsible' => TRUE,
+  );
+  $form['status_fieldset']['status'] = array(
+    '#type' => 'markup',
+    '#markup' => t('Queue status for queue @name:', array('@name' => $queue_name)) . '<br/>' . theme('queue_items', array('items' => $items)),
+  );
+  return $form;
+}
+
+/**
+ * Submit function for the insert-into-queue button.
+ */
+function queue_example_add_remove_form_insert($form, &$form_state) {
+  // Get a queue (of the default type) called 'queue_example_queue'.
+  // If the default queue class is SystemQueue this creates a queue that stores
+  // its items in the database.
+  $queue = DrupalQueue::get($form_state['values']['queue_name']);
+  $queue->createQueue();  // There is no harm in trying to recreate existing.
+
+  // Queue the string.
+  $queue->createItem($form_state['values']['string_to_add']);
+  $count = $queue->numberOfItems();
+  drupal_set_message(t('Queued your string (@string_to_add). There are now @count items in the queue.', array('@count' => $count, '@string_to_add' => $form_state['values']['string_to_add'])));
+  $form_state['rebuild'] = TRUE;  // Allows us to keep information in $form_state.
+  // Unsetting the string_to_add allows us to set the incremented default value
+  // for the user so they don't have to type anything.
+  unset($form_state['input']['string_to_add']);
+  $form_state['storage']['insert_counter']++;
+}
+
+/**
+ * Submit function for the "claim" button. Claims (retrieves) an item from
+ * the queue and reports the results.
+ */
+function queue_example_add_remove_form_claim($form, &$form_state) {
+  $queue = DrupalQueue::get($form_state['values']['queue_name']);
+  $queue->createQueue();  // There is no harm in trying to recreate existing.
+  $item = $queue->claimItem($form_state['values']['claim_time']);
+  $count = $queue->numberOfItems();
+  if (!empty($item)) {
+    drupal_set_message(t('Claimed item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', array('@count' => $count, '@item_id' => $item->item_id, '@string' => $item->data, '@seconds' => $form_state['values']['claim_time'])));
+  }
+  else {
+    drupal_set_message(t('There were no items in the queue available to claim. There are @count items in the queue.', array('@count' => $count)));
+  }
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Submit function for "Claim and delete" button.
+ */
+function queue_example_add_remove_form_delete($form, &$form_state) {
+  $queue = DrupalQueue::get($form_state['values']['queue_name']);
+  $queue->createQueue();  // There is no harm in trying to recreate existing.
+  $count = $queue->numberOfItems();
+  $item = $queue->claimItem(60);
+  if (!empty($item)) {
+    drupal_set_message(t('Claimed and deleted item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', array('@count' => $count, '@item_id' => $item->item_id, '@string' => $item->data, '@seconds' => $form_state['values']['claim_time'])));
+    $queue->deleteItem($item);
+    $count = $queue->numberOfItems();
+    drupal_set_message(t('There are now @count items in the queue.', array('@count' => $count)));
+  }
+  else {
+    $count = $queue->numberOfItems();
+    drupal_set_message(t('There were no items in the queue available to claim/delete. There are currently @count items in the queue.', array('@count' => $count)));
+  }
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Submit function for "run cron" button.
+ *
+ * Runs cron (to release expired claims) and reports the results.
+ */
+function queue_example_add_remove_form_run_cron($form, &$form_state) {
+  drupal_cron_run();
+  $queue = DrupalQueue::get($form_state['values']['queue_name']);
+  $queue->createQueue();  // There is no harm in trying to recreate existing.
+  $count = $queue->numberOfItems();
+  drupal_set_message(t('Ran cron. If claimed items expired, they should be expired now. There are now @count items in the queue', array('@count' => $count)));
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Submit handler for clearing/deleting the queue.
+ */
+ function queue_example_add_remove_form_clear_queue($form, &$form_state) {
+   $queue = DrupalQueue::get($form_state['values']['queue_name']);
+   $queue->deleteQueue();
+   drupal_set_message(t('Deleted the @queue_name queue and all items in it', array('@queue_name' => $form_state['values']['queue_name'])));
+ }
+
+/**
+ * Retrieve the queue from the database for display purposes only.
+ *
+ * It is not recommended to access the database directly, and this is only here
+ * so that the user interface can give a good idea of what's going on in the
+ * queue.
+ *
+ * @param $queue_name
+ *   The name of the queue from which to fetch items.
+ */
+function queue_example_retrieve_queue($queue_name) {
+  $items = array();
+  $result = db_query("SELECT item_id, data, expire, created FROM {queue} WHERE name = :name ORDER BY item_id",
+    array(':name' => $queue_name),
+    array('fetch' => PDO::FETCH_ASSOC));
+  foreach ($result as $item) {
+    $items[] = $item;
+  }
+  return $items;
+}
+
+/**
+ * Theme the queue display.
+ *
+ * Again, this is not part of the demonstration of the queue API, but is here
+ * just to make the user interface more understandable.
+ *
+ * @param $variables
+ */
+function theme_queue_items($variables) {
+  $items = $variables['items'];
+  $rows = array();
+  foreach ($items as &$item) {
+    if ($item['expire'] > 0) {
+      $item['expire'] = t("Claimed: expires %expire", array('%expire' => date('r', $item['expire'])));
+    }
+    else {
+      $item['expire'] = t('Unclaimed');
+    }
+    $item['created'] = date('r', $item['created']);
+    $item['content'] = check_plain(unserialize($item['data']));
+    unset($item['data']);
+    $rows[] = $item;
+  }
+  if (!empty($rows)) {
+    $header = array(t('Item ID'), t('Claimed/Expiration'), t('Created'), t('Content/Data'));
+    $output = theme('table', array('header' => $header, 'rows' => $rows));
+    return $output;
+  }
+  else {
+    return t('There are no items in the queue.');
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function queue_example_theme() {
+  return array(
+    'queue_items' => array(
+      'variables' => array('items' => NULL),
+    ),
+  );
+}
\ No newline at end of file
diff --git queue_example/queue_example.test queue_example/queue_example.test
new file mode 100644
index 0000000..ca8ef37
--- /dev/null
+++ queue_example/queue_example.test
@@ -0,0 +1,59 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Test the queue example module.
+ */
+class QueueExampleTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Queue Example functionality',
+      'description' => 'Test Queue Example functionality',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Enable modules and create user with specific permissions.
+   */
+  function setUp() {
+    parent::setUp('queue_example');
+  }
+
+  /**
+   * Login user, create an example node, and test blog functionality through the admin and user interfaces.
+   */
+  function testQueueExampleBasic() {
+
+    // Load the queue with 5 items.
+    for ($i = 1; $i <= 5; $i++) {
+      $edit = array('string_to_add' => $i);
+      $this->drupalPost('queue_example/insert_remove', $edit, t('Insert into queue'));
+      $this->assertText(t('There are now @number items in the queue', array('@number' => $i)));
+    }
+    // Claim each of the 5 items with a claim time of 0 seconds.
+    for ($i = 1; $i <= 5; $i++) {
+      $edit = array('claim_time' => 0);
+      $this->drupalPost(NULL, $edit, t('Claim the next item from the queue'));
+      $this->assertPattern(t('%Claimed item id=.*string=@string for 0 seconds.%', array('@string' => $i)));
+    }
+    $edit = array('claim_time' => 0);
+    $this->drupalPost(NULL, $edit, t('Claim the next item from the queue'));
+    $this->assertText(t('There were no items in the queue available to claim'));
+
+    // Run cron to release expired items.
+    $this->drupalPost(NULL, array(), t('Run cron manually (to expire claimed items)'));
+    // Claim and delete each of the 5 items which should now be available.
+    for ($i = 1; $i <= 5; $i++) {
+      $edit = array('claim_time' => 0);
+      $this->drupalPost(NULL, $edit, t('Claim the next item and delete it'));
+      $this->assertPattern(t('%Claimed and deleted item id=.*string=@string for 0 seconds.%', array('@string' => $i)));
+    }
+    // Verify that nothing is left to claim.
+    $edit = array('claim_time' => 0);
+    $this->drupalPost(NULL, $edit, t('Claim the next item from the queue'));
+    $this->assertText(t('There were no items in the queue available to claim'));
+  }
+}
