参考链接:
http://tutorials.jenkov.com/java-concurrency/blocking-queues.html
http://tutorials.jenkov.com/java-concurrency/thread-pools.html
阻塞队列
阻塞队列是一个可以阻塞线程的队列。当你尝试向空队列中弹出元素时,会被阻塞,直到入队一个新元素。当向满队列写入元素时,会被
阻塞,直到出队一个元素。
一个简单的阻塞队列实现如下:
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();
}
}
}