我们都知道线程池有很多好处:
通过重复利用已经创建好的线程,可以减少创建线程时的资源消耗。
如果不限制线程的数量,不仅会大量消耗系统内存,还会照成系统的不稳定。
使用线程池,可以控制线程的数量,还可以对所有线程进行统一的管理,好处不言而喻。
那么在详细了解线程池之前。我们需要先复习一些概念
一。阻塞队列(BlockingQueue)
先看一下阻塞队列的代码关系:interface BlockingQueue<E> extends Queue<E>
我们发现这是一个继承了Queue的接口。BlockingQueue有什么特性呢?我们做以下功课:
二。我们先看看最原始接口Queue Interface的方法:
java源码注释已经帮我们分类好了:
最原始的Queue Interface有两种类型的插入,删除,和获取元素方法,归类如下:
Throws Exception | Special Value | |
插入类 | add(o) | offer(o) |
删除类 | remove(o) | poll(o) |
获取类 | element(o) | peek(o) |
这两个类型的返回意义如下:
- Throws Exception:
如果这个操作不能立即执行,那么抛出异常 - Special Value:
如果这个操作不能立即执行,那么相应返回(true/false)
三。我们再看看BlockingQueue Interface的方法
java 源码注释里面已经很清楚帮我们分类好了
BlockingQueue有四种类型的插入,删除,和获取元素方法,归类如下:
Throws Exception | Special Value | Blocks | Times Out | |
插入类 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
删除类 | remove(o) | poll(o) | take(o) | poll(timeout, timeunit) |
获取类 | element(o) | peek(o) |
Throws Exception: 这四各类型的返回意义如下:
- 如果这个操作不能立即执行,那么抛出异常
- Special Value:
如果这个操作不能立即执行,那么相应返回(true/false) - Blocks:
如果这个操作不能立即执行,那么操作阻塞等待,直到操作可以执行。 - Times Out:
如果这个操作不能立即执行,那么操作阻塞等待,直到操作可以执行,但是有限定时间,如果超过时间还没有完成,就会返回错误信息(false)
我们可以很明显的看到BlockingQueue加入了阻塞等待的操作,可以理解成如果队列满了,插入任务就在门口等着,不抛出错误信息,直到有元素从队列中取出,队列有空位了,再进行插入操作,相应的你还可以加入等待超时机制,如果过时了,就不等了。
我们写个例子看看:
package test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueTest {
public static void main(String[] args) {
//初始化队列长度只有3的队列
final BlockingQueue<String> blockingque = new ArrayBlockingQueue<String>(3);
Thread Putter = new Thread(new Runnable(){
@Override
public void run() {
for(int i=1;i<10;i++){
try {
blockingque.put("货物"+i);
System.out.println("成功往队列中放入货物"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Putter.start();
Thread taker = new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
//取得时间延长,模拟取得时间远大于放入时间
Thread.sleep(3000);
String cargo = blockingque.take();
System.out.println("取出货物: "+cargo);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
taker.start();
}
}
输出结果为:
成功往队列中放入货物1
成功往队列中放入货物2
成功往队列中放入货物3
取出货物: 货物1
成功往队列中放入货物4
取出货物: 货物2
成功往队列中放入货物5
取出货物: 货物3
成功往队列中放入货物6
取出货物: 货物4
成功往队列中放入货物7
取出货物: 货物5
成功往队列中放入货物8
取出货物: 货物6
成功往队列中放入货物9
取出货物: 货物7
取出货物: 货物8
取出货物: 货物9
我们可以看到队列长度为3,队列放满3个后,put()方法就处于blocking的状态等待队列有位子
过了3秒后,getter开始从队列中取货物,一有空位,put()方法就得以继续执行。
二。interface BlockingQueue的实现
由于BlockingQueue只是一个接口,需要类实现,java已经有了以下的几个类实现BlockingQueue(java 6)
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
最主要的,还是BlockingQue的Blocking概念,在以后线程池的实现中有很大用处