最近搞了个项目,涉及到多线程编程,同时呢,有涉及线程需要返回结果的功能。
首先,介绍一下ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略
handler有四个选择:
ThreadPoolExecutor.AbortPolicy()
抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()
重试添加当前的任务,他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务
// 构造一个线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());
在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。
这个小组里面队员至少有两个,如果他们两个忙不过来,任务就被放到任务列表里面。
如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员,至多只能雇佣 4个。
如果四个队员都在忙时,再有新的任务,这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发,直到接受这个任务为止(更残忍!呵呵)。
因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。
以上是参考别人的博客,感觉写的真的不错,尤其是这个例子,通俗易懂。
下面是两种线程的需求:
1、线程需要有返回值
实现callable接口的 call方法
思路:
可以在call里写循环,创建线程类的时候用List、Map等集合来传参
class
ShortenUrl
implements
Callable<List<Map<String, String>>>{
@Override
public
List<Map<String, String>> call()
throws
Exception {
return
backList;
}
}
调用时:
private static final int
size
=
1000;
private final static
ExecutorService
pool
= ThreadPoolExecutorUtil.getInstance().getThreadPoolExecutorService();
CompletionService<List<Map<String, String>>> urlThreadService =
new
ExecutorCompletionService<>(pool);
使用这个urlThreadService 进行创建线程
urlThreadService.submit(
new
ShortenUrl(threadUrlRecordList, url_long_Map, url_key_Map,
thread_message_Map, messageMap_Map, batch_id));
使用这个方式判断线程是否执行完毕
for(int
i =
0; i< urlThreadCount; ++i){
try
{
List<Map<String,
String>> back = urlThreadService.take().get();
if(null
!= back && back.size() >
0){
fromUrlThreadList.addAll(back);
}
}
catch
(InterruptedException | ExecutionException e) {
logger.error("线程等待异常:{}",
e);
}
}
2、线程不需要返回值
实现Runnable接口的 run方法
class
MySendSmsThread
implements
Runnable{
@Override
public void
run(){
finally
{
doneSignal.countDown();
}
}
}
final
CountDownLatch doneSignal =
new
CountDownLatch(threadCount);
try{
doneSignal.await();
logger.info("\n
线程执行完毕 jobSms:{}", jobSms.getId());
}catch
(InterruptedException e) {
logger.error("线程等待异常:{}",
e);
}
可以使用doneSignal 进行线程是否执行的判断
int
total = sendDataMap.size();
int
threadCount = (int)
(total / size
+ ((total %
size
!=
0) ?
1
:
0));
使用这种办法设置线程数量
for(int
j =
0; j< threadCount; ++j){
int
startIndex = j *
size;
int
toIndex = ((j +
1) *
size) > sendSmsList.size()
? sendSmsList.size() : (j + 1) *
size;
List<NewSendSms> threadRecordList = sendSmsList.subList(startIndex, toIndex);
ThreadPoolExecutorUtil.getInstance().getThreadPoolExecutorService()
.execute(new
GetStatusThread(batchNo, threadRecordList, doneSignal));
调用
}
使用这种办法获得每个线程中的List
这个LinkedBlockingQueue,有兴趣的话可以去查查为什么使用这个队列作为实现方式
public class ThreadPoolExecutorUtil {
public static final int NTHREADS = 200;// 默认线程池个数
private ThreadPoolExecutorUtil() {
}
private volatile static ThreadPoolExecutorUtil INSTANCE;
private static final LinkedBlockingQueue<Runnable> QUEUE = new LinkedBlockingQueue<>(5000);// 后续应加入队列长度监听机制
private ExecutorService executorService = new ThreadPoolExecutor(NTHREADS, NTHREADS, 0L, TimeUnit.MILLISECONDS,
QUEUE);
public static ThreadPoolExecutorUtil getInstance() {
if (null == INSTANCE) {
synchronized (ThreadPoolExecutorUtil.class) {
if (null == INSTANCE) {
INSTANCE = new ThreadPoolExecutorUtil();
}
}
}
return INSTANCE;
}
public ExecutorService getThreadPoolExecutorService() {
if (null == executorService) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(NTHREADS, NTHREADS, 0L, TimeUnit.MILLISECONDS, QUEUE);
/**
* 重写Rejected策略,缺省抛出TaskRejectedException异常,然后不执行
* 当pool已经达到maxsize的时候 不在新线程中执行任务,而是有调用者所在的线程来执行
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
return executorService;
}
@PreDestroy
public void destroy() {
executorService.shutdown();
}
}
刚刚接触,如有错误还请各位大牛指出