在java中,在并发的情况可以使用ThreadPoolExecutor,但为了提高吞吐量和性能,可以扩展ThreadPoolExecutor。
ThreadPoolExecutor的执行流程:
- 当core线程数大于当前任务数时,可以创建新的线程;
- 当core线程数小于当前执行的任务数时,则将任务加入到队列;
- 当队列已满时,则开始创建新的线程,当线程数达到max线程数时,则会抛出RejectedExcutionException异常。
这样也行会出现一个问题,如果当任务数不断增大,core线程数已不足于应付时,就会频繁的将任务加入队列,不断的创建队列,加入队列,对性能具有很大影响,如果队列设置较大时,max线程则很少会使用到,那么不妨考虑以下实现方式也行会更好些:
- 当core线程数大于当前任务数时,可以创建新的线程;
- 当core线程数小于当前执行的任务数时,而当前任务数小于max线程数时,则创建新的线程运行任务;
- 当max线程数无法应付时,在将任务加入队列,如队列满时,在抛出RejectedExcutionException异常。
这样实现最大的利用了可用线程数,减少了创建队列加入队列的系统消耗。以下为代码实现:
自定义ThreadPoolExecutor:
public class ThreadPoolExecutorExtend extends java.util.concurrent.ThreadPoolExecutor{
private final AtomicInteger atomicInt = new AtomicInteger(0);
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, TaskQueue workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
workQueue.setExecutor(this);
}
@Override
public void execute(Runnable command) {
try{
atomicInt.incrementAndGet();
super.execute(command);
}catch(Exception e){
((TaskQueue)super.getQueue()).offer(command);
}
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
atomicInt.decrementAndGet();
super.afterExecute(r, t);
}
public int getSubmitTask(){
return atomicInt.get();
}
}
自定义LinkedBlockingQueue:
public class TaskQueue extends java.util.concurrent.LinkedBlockingQueue<Runnable>{
private static final long serialVersionUID = 2804119236686921894L;
private ThreadPoolExecutorExtend executor;
public TaskQueue(int size) {
super(size);
}
@Override
public boolean offer(Runnable e) {
// current task size
int currentTask = executor.getPoolSize();
if(currentTask < executor.getMaximumPoolSize()){
return false;
}
return super.offer(e);
}
public void setExecutor(ThreadPoolExecutorExtend e){
executor = e;
}
}
测试类:
public class MyThreadPoolTest {
public static void main(String[] args) {
int corePoolSize = 5;
int maximumPoolSize = 10;
int keepAliveTime = 60;
final ThreadPoolExecutorExtend pool = new ThreadPoolExecutorExtend(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new TaskQueue(5));
for(int i=0;i<15;i++){
pool.execute(new Runnable() {
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("当前线程:"+pool.getPoolSize()+",当前队列数量:"+pool.getQueue().size());
}
}
}
运行结果如下:
当前线程:1,当前队列数量:0
当前线程:2,当前队列数量:0
当前线程:3,当前队列数量:0
当前线程:4,当前队列数量:0
当前线程:5,当前队列数量:0
当前线程:6,当前队列数量:0
当前线程:7,当前队列数量:0
当前线程:8,当前队列数量:0
当前线程:9,当前队列数量:0
当前线程:10,当前队列数量:0
当前线程:10,当前队列数量:1
当前线程:10,当前队列数量:2
当前线程:10,当前队列数量:3
当前线程:10,当前队列数量:4
当前线程:10,当前队列数量:5
可用将TaskQueue类中重写offer方法注释掉,再次运行测试类,看运行结果,即可看到区别。