通过ThreadPoolExecutor 进行多线程编程

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

首先,介绍一下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();
    }
}

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


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值