'Initialize an AdaptiveThreadPool.
An adaptive thread pool executes WorkItems using a number of
WorkerThreads.  WorkItems represent items of work that may
succeed, soft fail, or hard fail. In addition, a completed work
item can signal this AdaptiveThreadPool to enable more or fewer
threads.  Initially one thread is active.  Soft failures are
reqeueud to be retried.  Hard failures cause this
AdaptiveThreadPool to shut down entirely.  See the WorkItem class
for more details.
Args:
num_threads: The number of threads to use.
queue_size: The size of the work item queue to use.
base_thread_name: A string from which worker thread names are derived.
worker_thread_factory: A factory which procudes WorkerThreads.
queue_factory: Used for dependency injection.'

def __init__(self, num_threads, queue_size=None, base_thread_name=None, worker_thread_factory=WorkerThread, queue_factory=Queue.Queue):

    if (queue_size is None):
        queue_size = num_threads
    self.requeue = ReQueue(queue_size, queue_factory=queue_factory)
    self.__thread_gate = ThreadGate(num_threads)
    self.__num_threads = num_threads
    self.__threads = []
    for i in xrange(num_threads):
        thread = worker_thread_factory(self, self.__thread_gate)
        if base_thread_name:
            base = base_thread_name
        else:
            base = thread.__class__.__name__
        thread.name = ('%s-%d' % (base, i))
        self.__threads.append(thread)
        thread.start()
