通过ThreadPoolExecutor 进行多线程编程

来源:互联网 发布:python sorted函数 编辑:程序博客网 时间:2024/04/28 02:14

最近搞了个项目,涉及到多线程编程,同时呢,有涉及线程需要返回结果的功能。

首先,介绍一下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等集合来传参
classShortenUrlimplementsCallable<List<Map<String, String>>>{
@Override
publicList<Map<String, String>> call()throwsException {
returnbackList;
}
}

调用时:
private static final intsize=1000;

private final staticExecutorServicepool= ThreadPoolExecutorUtil.getInstance().getThreadPoolExecutorService();

CompletionService<List<Map<String, String>>> urlThreadService =
newExecutorCompletionService<>(pool);

使用这个urlThreadService 进行创建线程
urlThreadService.submit(
newShortenUrl(threadUrlRecordList, url_long_Map, url_key_Map,
thread_message_Map, messageMap_Map, batch_id));

使用这个方式判断线程是否执行完毕
for(inti =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方法
classMySendSmsThreadimplementsRunnable{
@Override
public voidrun(){

finally{
doneSignal.countDown();
}

}
}
finalCountDownLatch doneSignal =newCountDownLatch(threadCount);
try{
doneSignal.await();
logger.info("\n 线程执行完毕 jobSms:{}", jobSms.getId());
}catch(InterruptedException e) {
logger.error("线程等待异常:{}", e);
}
可以使用doneSignal 进行线程是否执行的判断

inttotal = sendDataMap.size();
intthreadCount = (int) (total / size+ ((total %size!=0) ?1:0));
使用这种办法设置线程数量

for(intj =0; j< threadCount; ++j){
intstartIndex = j *size;
inttoIndex = ((j +1) *size) > sendSmsList.size() ? sendSmsList.size() : (j + 1) *size;
List<NewSendSms> threadRecordList = sendSmsList.subList(startIndex, toIndex);
ThreadPoolExecutorUtil.getInstance().getThreadPoolExecutorService()
.execute(newGetStatusThread(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();    }}

刚刚接触,如有错误还请各位大牛指出


原创粉丝点击