BlockingQueue.java :  » Web-Server » simple » simple » util » Java Open Source

Java Open Source » Web Server » simple 
simple » simple » util » BlockingQueue.java
/*
 * BlockingQueue.java February 2001
 *
 * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA  02111-1307  USA
 */
 
package simple.util;

import java.io.Serializable;

/**
 * This provides a quick implementation for a thread safe queue. This
 * ensures that if there are several threads enqueuing or dequeuing
 * from this queue that no thread will dequeue a null.
 * <p>
 * This will block a thread from dequeuing when there is not items 
 * in the queue. It will also block an enqueuer if there is no space 
 * left in the queue. 
 * <p>
 * When a thread is waiting and gets notified by another thread the 
 * thread that has been notified reasserts the check for the full 
 * or empty case, this means that there will be no problems if there 
 * are several enqueuing threads and several dequeuing threads.
 *
 * @author Niall Gallagher
 */ 
public class BlockingQueue implements Serializable{

   /**
    * The number of objects in the queue.
    */
   private volatile int count;

   /**
    * This is where the objects are stored.
    */
   private Object[] queue;

   /**
    * Offset where objects are dequeued from. 
    */
   private int front;

   /**
    * Offset where objects are enqueued to.
    */
   private int rear;

   /**
    * The number of objects that can be enqueued.
    */
   private int capacity;

   /**
    * The number of threads waiting to dequeue.
    */
   private int enqueuing;

   /**
    * The number of threads waiting to dequeue.
    */
   private int dequeuing;    
    
   /**
    * When the size of the <code>BlockingQueue</code> is not specified
    * then the default size of 30 is set, this <code>BlockingQueue</code> 
    * cannot resize so care is need when picking a size.
    */     
   public BlockingQueue() {
      this(30);
   }

   /**
    * If the capacity given is less than 1 then the size of
    * the queue is increased so that it becomes 1 this means
    * that the queue can tolerate at least one add by a thread.
    *
    * @param capacity the initial size that this queue can handle
    */     
   public BlockingQueue(int capacity) {
      this.capacity = capacity < 1 ? 1 : capacity;   
      this.rear = this.capacity - 1;
      this.queue = new Object[capacity];       
   }
   
   /**
    * If this enqueues to an empty queue it notifys any dequeuers
    * that were trying to take from the empty queue. This ensures
    * that a dequeuer can wake-up an will not block indefinitely.
    *
    * @param object the object to enqueue into this
    * <code>BlockingQueue</code>.
    * @exception InterruptedException if an interrupt is issued.
    */       
   public void enqueue(Object object) throws InterruptedException {       
      synchronized(queue) {  
         enqueuing(); 
         count++;
         rear = (rear + 1) % capacity;
         queue[rear] = object;
      }
   }

   /**
    * If this dequeues from a full queue it notifys any enqueuers who
    * were waiting to add to the full queue, so that they do not block.
    *
    * @return an object from the queue, this will never be a null object
    *
    * @exception InterruptedException is thrown if an interrupt is
    * issued
    */       
   public Object dequeue() throws InterruptedException {
      synchronized(queue) {
         dequeuing();
         Object object = queue[front];
         queue[front] = null;
         count--;
         front = (front + 1) % capacity;
         return object;
      }
   }

   /**
    * In 'enqueuing' there is no waste in notification because if there
    * is dequeuer's then that means that there cannot be also enqueuer's
    * because the wait condition would fail for the enqueuer. For example
    * if a dequeuer was waiting on the lock and an enqueuer came along, 
    * it would release that dequeuer, however if a number of dequeuer's 
    * came along they would all be waiting for the 'queue' lock, no 
    * enqueuer can ever be waiting with it also because when an enqueuer 
    * comes along it would automatically pass the while condition and 
    * release the waiting dequeuer, vice-versa.
    *
    * @exception InterruptedException if an interrupt is issued to
    * the enqueuing thread
    */ 
   private void enqueuing() throws InterruptedException {
      while(count == capacity) {
         enqueuing++;
         try {
            queue.wait();
         } finally {
            enqueuing--;
         }
      }
      if(dequeuing > 0) {
         queue.notify();            
      }
   }
   
   /**
    * As above for 'enqueuing' there will never be enqueuers and
    * dequeres waiting at the same time, it will either be all
    * enqueuer's or all dequeuer's waiting to be notified and only an
    * enqueuer can notify a dequeuer as well as only a dequeuer can
    * notify a enqueuer. This does an iterative check because of the
    * semantics of the wait/notify paradigm. When a dequeuer is
    * waiting to be notified it will add 1 to the dequeuers count. When
    * there are several dequeuers this means that there is nothing in
    * the object queue, the enqueue method will then detect that there
    * are dequeuers and notify one of them. This however does not mean
    * that the thread that has been notified will be the next to grab the
    * lock. The notified thread must wait its turn before it can grab the
    * lock, this means that there could have been some thread that took
    * the only enqueued item. Once the notified thread regains the lock
    * it will have to detect wheather another thread dequeued the only
    * object, if this is the case the thread must wait again to be
    * notified.
    *
    * @exception InterruptedException if interrupt is issued to the
    * thread to the dequuer
    */       
   private void dequeuing() throws InterruptedException {
      while(count == 0) { 
         dequeuing++;
         try {
            queue.wait();
         }finally{
            dequeuing--;
         }
      }       
      if(enqueuing > 0) {
         queue.notify();
      }
   }  

   /**
    * This returns the number of objects that are actually enqueued
    * into the <code>BlockingQueue</code>. If the length is zero then 
    * a dequeue method will block.
    *
    * @return the number of objects that is currently in the queue
    */ 
   public int length() {
      return count;
   }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.