使用threadpoolExecutor,主要是任务的提交的执行和获取结果。
提交任务的方法有:
1、submit 2、execute 3、queue的add
其中1和2的使用必须是threadpoolExecutor的实例,直接提交。两种做法:1、暴露threadpool实例,2、封装threadpool,然后提供一个代理或decorator类似的东西进行任务提交。
联系到threadpoolexecutor内部使用的queue是blockingqueue:阻塞读取和插入,可以利用该queue作为管道,输送任务对象,而threadpool实例直接等待队列的数据。
BUT,问题在于threadpoolExecutor在实例化之后(new),池子是空的,并不会自动将线程数(taskRunner的数)初始化,怎么使其初始化呢(有了线程后,线程在timeout时间内等待任务,若需要其不用timeout呢,直接为0即可):可以在初始化之后先添加一个或多个空任务:
1 queue = new CrawTaskBlockingQueue(capacity); 2 executors = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, queue); 3 //模拟开始
for (int i = 0; i < corePoolSize; i++) 4 executors.submit(new Callable<T>() { 5 6 public T call() { 7 LogUtil.debug(logger, "executors test start..........."); 8 return null; 9 } 10 });
任务启动后,只需要向queue提交任务即可:
1 queue.offer(task);
当然,这样做的问题比较大:
1、直接往threadpool提交任务时,如果threadpool 没有到达最大线程数,会直接创建线程执行任务,而不会进去queue;这种方式的统一入口却是queue:统一入queue,而且maxpoolSize>corepoolSize时,thread不会增加,是个弊端。
2、Threadpool有RejectedExecution的机制,在无法往queue中offer的时候,会调用一个拒绝机制。而直接调用add方法,一般的queue实现中,会尝试一下offer,没有拒绝以后的机制。但是如果没有特殊reject的指定,这一条不使用也没什么。直接queue的插入阻塞即可满足。