线程池&阻塞队列实现--笔记

参考链接:

http://tutorials.jenkov.com/java-concurrency/blocking-queues.html

http://tutorials.jenkov.com/java-concurrency/thread-pools.html

阻塞队列

A BlockingQueue with one thread putting into it, and another thread taking from it.

阻塞队列是一个可以阻塞线程的队列。当你尝试向空队列中弹出元素时,会被阻塞,直到入队一个新元素。当向满队列写入元素时,会被

阻塞,直到出队一个元素。

一个简单的阻塞队列实现如下:

public class BlockingQueue {

  private List queue = new LinkedList();
  private int  limit = 10;//队列容量

  public BlockingQueue(int limit){
    this.limit = limit;
  }


  //入队,加入一个元素,如果满了,则等待,未满则加入元素
  public synchronized void enqueue(Object item)
  throws InterruptedException  {
    while(this.queue.size() == this.limit) {//如果满了,则等待
      wait();
    }
    if(this.queue.size() == 0) {//队列个数为0时,可能会有线程因为出队操作导致等待,因此需要唤醒
      notifyAll();
    }
    this.queue.add(item);//未满,添加元素
  }

  //出队,如果队列为空,则等待,否则出队一个元素
  public synchronized Object dequeue()
  throws InterruptedException{
    while(this.queue.size() == 0){//此时队列为空,因此等待
      wait();
    }
    if(this.queue.size() == this.limit){//理由类似,唤醒等待线程
      notifyAll();
    }

    return this.queue.remove(0);//出队并返回
  }

}

线程池

开启一个新线程会带来一定的性能和内存开销。每当来一个任务时便开启一个线程来处理此任务,会延长处理时间,并且线程过多时,上下文切换耗费的时间会更多,带来严重的性能开销,内存开销也会大大增加。如果刚开始就建立一个规定数量的线程池,每次来一个任务时只需将该任务分给一个空闲的线程即可。如果没有空闲的线程就等待。那么没有建立线程的开销,线程数量也被规定好了,响应速度也被提高了。

下面描述一下代码中实现线程池的思想。线程池类ThreadPool含有一定的线程(PoolThread),放在容器threads中,和一个任务队列taskQueue,该队列就是上面所获的阻塞队列(BlockingQueue)。先初始化阻塞队列,设置队列的容量大小。再初始化线程,每个线程都会被启动。被启动的线程会一定循环,循环体内不断尝试从队列中取出任务,然后调用任务的处理函数来执行任务。如果没有任务就被阻塞,直到有任务为止。当任务来临时,通过调用线程池的execute函数将任务放入到队列中,如果队列满了便被阻塞。

下面看看加入了详细注释的代码,一共两个类。

public class PoolThread extends Thread {

    private BlockingQueue taskQueue = null;
    private boolean       isStopped = false;

    public PoolThread(BlockingQueue queue){//通过构造函数从线程池中获得队列的引用
        taskQueue = queue;
    }

    public void run(){
        while(!isStopped()){//如果没有被停止
            try{
                Runnable runnable = (Runnable) taskQueue.dequeue();//从队列中取出任务,该任务是一个Runnable接口的对象
                runnable.run();//处理任务,该任务不会建立新线程,只会在该线程中运行。
            } catch(Exception e){//捕获被调用doStop中interrupt函数中断时产生的异常
                //log or otherwise report exception,
                //but keep pool thread alive.
            }
        }
    }

    //结束该线程,interrupt函数将使该线程从dequeue函数中中断出来
    public synchronized void doStop(){
        isStopped = true;
        this.interrupt(); //break pool thread out of dequeue() call.
    }

    public synchronized boolean isStopped(){
        return isStopped;
    }
}
public class ThreadPool {

    private BlockingQueue taskQueue = null;//任务队列
    private List<PoolThread> threads = new ArrayList<PoolThread>();//线程池
    private boolean isStopped = false;

    //noOfThreads为线程池中线程的个数,maxNoOfTasks为线程任务的最大个数,也就是队列的容量
    public ThreadPool(int noOfThreads, int maxNoOfTasks){
        taskQueue = new BlockingQueue(maxNoOfTasks);//初始化队列

        //初始化线程并运行
        for(int i=0; i<noOfThreads; i++){
            threads.add(new PoolThread(taskQueue));//建立线程
        }
        for(PoolThread thread : threads){
            thread.start();//运行线程
        }
    }

    //将任务放入任务队列中,如果队列满了将阻塞该线程。如果线程被停止仍调用该函数会抛出异常
    public synchronized void  execute(Runnable task) throws Exception{
        if(this.isStopped) throw
            new IllegalStateException("ThreadPool is stopped");

        this.taskQueue.enqueue(task);
    }

    public synchronized void stop(){
        this.isStopped = true;
        for(PoolThread thread : threads){
           thread.doStop();
        }
    }

}

猜你喜欢

转载自blog.csdn.net/jdbdh/article/details/81953166