JAVA线程池

JAVA线程池

基本用法

先来看个基本用法

ExecutorServiceexecutor=Executors.newFixedThreadPool(3);
executor.execute(newRunnable() {
   
@Override
   
public void run() {
       
//do something
   
}
})
;

 

上边代码创建了一个线程池,里面是有固定3个线程的线程池,然后使用execute执行一个任务,把这个runnable丢到线程池里执行。

概述

ExecutorService是线程池的管理类

Executor是线程池创建的工厂类

创建线程池一般会调用Executor的newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor的这四个方法之一,来创建需要的线程池。

线程池,一般有几个基本参数

corePoolSize 核心线程数

maximumPoolSize 最大线程数

keepAliveTime超时时间

 

线程池的类是ThreadPoolExecutor,corePoolSize的作用主要是控制线程的停止。

只要线程数大于corePoolSize,就会触发以下逻辑。如果某个线程执行完他的任务了,会尝试去任务队列中取,如果在keepAliveTime内没取到任务(可能任务队列为空),那就会停止此线程,并且提醒其他idle的线程也停止,这样总线程数就降下来了。

而线程数降到corePoolSize之后就不会去停止线程了。这样线程池中一直会有corePoolSize个线程,所以有人称为核心线程,当然要记住核心线程不是一种特殊的线程,说不定这个时候线程池里的核心线程是这些,过一会线程池里的核心线程是另一些了,核心线程只是线程池的一种概念,并不是指某个线程的属性。

还有一种特殊情况,如果把allowCoreThreadTimeOut设置为true,那corePoolSize就无法控制线程的停止了,任何线程只要空闲时间超过keepAliveTime就会停止

 

线程池执行任务规则如下:

1、        初始状态线程池内没有线程,来了任务,就会立刻创建线程。

2、        当前线程数小于corePoolSize,那就来一个任务,创建一个线程。

3、        当前线程数达到corePoolSize,来了个任务,那就丢到任务队列里面去排队,等待某个线程执行完他当前的任务再来任务队列中取

4、        如果任务队列也满了,但是当前总线程数不超过maximumPoolSize,那就启动一个额外线程来处理。此时的线程数大于corePoolSize,小于maximumPoolSize,此时会触发线程闲置久了就停止的逻辑。

5、        如果任务队列也满了,但是当前总线程数到达maximumPoolSize,那就拒绝执行任务,调用一个RejectedExecutionHandler的rejectedExecution来通知调用者。


相关代码可以查看java.util.concurrent.ThreadPoolExecutor#execute



我们再来看看刚才四种方法产生的不同的线程池。

newFixedThreadPool

newFixedThreadPool得到的是ThreadPoolExecutor,里面只有核心线程,没有非核心线程,所有线程都处于活动状态,核心线程的数量固定,任务队列大小没有限制。所以,只用考虑上边的规则1和规则2。来了任务之后,核心线程有空就交给核心线程处理,核心线程没空就在任务队列里等待。所有线程一直开启,可以很快的响应任务,但是闲置状态比较浪费资源。适合处理少量耗时大的任务。

代码如下

return new ThreadPoolExecutor(nThreads, nThreads,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());

 newCachedThreadPool

newCachedThreadPool得到的也是ThreadPoolExecutor,与newFixedThreadPool对比很明显,newCachedThreadPool得到的线程池,没有核心线程,只有非核心线程,线程的最大数量是Integer.MAX_VALUE,所有线程的闲置时间不能超过60s,否则会被回收。这里的任务队列是SynchronousQueue,可以看做空,无法存储任务,那么一个任务到来之后,就检查是否有闲置的线程,有就交给闲置的线程去处理,如果没有就新开启一个线程去处理。闲置状态所有线程都会因为超时被停止,占资源少。有了任务得去开启线程,响应没有FixedThreadPool来的快,适合频繁的低耗时任务。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

 

 newScheduledThreadPool

newScheduledThreadPool得到的是ScheduledThreadPoolExecutor,他是ThreadPoolExecutor的子类。这个线程池里有一定数量的核心线程,也有非核心线程,线程总数量为Integer.MAX_VALUE。非核心线程的保活时间为10ms,一般用完就很快被回收。

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

 

这个线程池的主要用法如下,主要是用于带控制的任务,比如多久时间以后执行某个任务,按什么样的周期执行任务,主要用于定时执行任务。

public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit)

 

典型用法:

//在2000ms之后执行某个任务

pool.schedule(runnable,2000,TimeUnit.MILLISECONDS)


//10ms之后执行,2000ms执行依次

pool.scheduleAtFixedRate(runnable,10,2000,TimeUnit.MILLISECONDS)

周期性的执行任务的时候,如果其中某次出了异常,那就会中断,不在继续执行任务。所有最好把任务加上异常捕获。

比如

  private static class BusinessTask implements Runnable{
       @Override
       public void run() {
           //捕获所有的异常,保证定时任务能够继续执行
           try{
                System.out.println("任务开始...");
                //doBusiness();
                System.out.println("任务结束...");
           }catch (Throwable e) {
                // donothing
           }
       }
    }


 newSingleThreadExecutor

再来看newSingleThreadExecutor,这个得到的线程池和前面几个都不同,得到FinalizableDelegatedExecutorService,其他几个都是ThreadPoolExecutor或者他的子类。这个类顾名思义就是,本质上只有一个线程。所有任务都会依次在这个任务中执行,可以有效保证顺序。比如打日志到sd卡时,就必须保证有序。

 

如何配置线程池大小:

  一般需要根据任务的类型来配置线程池大小:

  如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1

  如果是IO密集型任务,参考值可以设置为2*NCPU


  当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

 参考文献

android开发艺术探索

https://segmentfault.com/a/1190000000371905

http://blog.csdn.net/nei504293736/article/details/7534084

http://www.cnblogs.com/dolphin0520/p/3932921.html


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值