线程池其他相关内容

11 篇文章 0 订阅
3 篇文章 0 订阅
一、提交任务到线程池中

向线程池中提交任务有两种方式:调用execute()和submit()方法

execute()方法:

用于提交不需要有返回值的任务,这类任务无法判断任务是否被线程池执行成功。
调用示例代码如下:(参数为一个Runnable类的实例)

executor.execute(new Runnable(){
        @Override
        public void run(){
                // do something
        }
});

submit()方法:

用于提交需要有返回值的任务,这类任务会返回一个future类型的对象,通过这个对象可以判断任务是否执行成功,并可以通过future的get()方法来获取返回值。
1、get()方法会阻塞当前线程直到任务完成
2、get(long timeout, TimeUnit unit)方法会阻塞当前线程指定的时间后返回,任务不一定执行结束。
调用示例代码如下:(参数为一个Runable类/Callable类的实例)

Future<Object> future = executor.submit(task);
if(future != null){
        try {
                Object obj = future.get();
        } catch(Exception e){
                // 异常处理
        } finally {
                // 关闭线程池
                executor.shutdown();
        }
}
二、关闭线程池

可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。
它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。

但是它们存在一定的区别:

shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,
shutdown只是将线程池状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。
当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。
至于应该调用哪一种方法关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。

三、配置线程池

要想合理地配置线程池,就必须首先分析任务特性,可以从以下几个角度来分析。

任务的性质:CPU密集型任务、IO密集型任务和混合型任务。
任务的优先级:高、中和低。
任务的执行时间:长、中和短。
任务的依赖性:是否依赖其他系统资源,如数据库连接。

性质不同的任务可以用不同规模的线程池分开处理。

CPU密集型任务应配置尽可能小的线程,如配置Ncpu+1个线程的线程池。
由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*Ncpu。
混合型的任务,如果可以拆分,将其拆分成一个CPU密集型任务和一个IO密集型任务
只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐量将高于串行执行的吞吐量。
如果这两个任务执行时间相差太大,则没必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。
优先级不同的任务可以使用优先队列PriorityBlockingQueue来处理。它可以让优先级高的任务先执行。

注意:如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。

执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先级队列,让执行时间短的任务先执行。

依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,等待的时间越长,则CPU空闲时间就越长,那么线程数应该设置得越大,这样才能更好地利用CPU。

建议使用有界队列。有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点。

四、线程池监控

如果在系统中大量使用线程池,则有必要对线程池进行监控,方便在出现问题时,可以根据线程池的使用状况快速定位问题。可以通过线程池提供的参数进行监控,在监控线程池的时候可以使用以下属性

属性作用
taskCount线程池需要执行的任务数量
completedTaskCount线程池在运行过程中已完成的任务数量,小于或等于taskCount
largestPoolSize线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过
largestPoolSize线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减
getActiveCount获取活动的线程数

通过扩展线程池进行监控:

可以通过继承线程池来自定义线程池,重写线程池的beforeExecute、afterExecute和terminated方法,可以在任务执行前、执行后和线程池关闭前执行一些代码来进行监控。

参考文件:Java并发编程的艺术
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值