最近搞了个项目,涉及到多线程编程,同时呢,有涉及线程需要返回结果的功能。
首先,介绍一下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();
}
}
刚刚接触,如有错误还请各位大牛指出