Android线程池(二)构造方法的参数详细说明
来源:互联网 发布:腾讯云免费域名 编辑:程序博客网 时间:2024/09/21 08:47
构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}
corePoolSize是线程池的目标大小,即是线程池刚刚创建起来,还没有任务要执行时的大小。maximumPoolSize是线程池的最大上限。keepAliveTime是线程的存活时间,当线程池内的线程数量大于corePoolSize,超出存活时间的空闲线程就会被回收。
如何使用
// 每次只执行一个线程任务的线程池 ExecutorService singleTaskExecutor = Executors.newSingleThreadExecutor(); // 限制线程池大小的线程池 ExecutorService limitedTaskExecutor = Executors.newFixedThreadPool(3); // 一个没有限制最大线程数的线程池 ExecutorService allTaskExecutor = Executors.newCachedThreadPool(); // 一个可以按指定时间可周期性的执行的线程池 ExecutorService scheduledTaskExecutor = Executors.newScheduledThreadPool(3); // 按指定工厂模式来执行的线程池 ExecutorService scheduledTaskFactoryExecutor = Executors.newFixedThreadPool(3, new ThreadFactoryTest()); ExecutorService scheduledTaskFactoryExecutor.submit(new Runnable() { @Override public void run() { Log.i("KKK", "This is the ThreadFactory Test submit Run! ! ! "); } });
private final int CORE_POOL_SIZE = 4;//核心线程数 private final int MAX_POOL_SIZE = 5;//最大线程数 private final long KEEP_ALIVE_TIME = 10;//空闲线程超时时间 private final int BLOCK_SIZE = 2;//阻塞队列大小 ThreadPoolExecutor executorPool = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(BLOCK_SIZE),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); executorPool.allowCoreThreadTimeOut(true); executorPool.execute(new WorkerThread(""));
使用预设的线程池
我们可以直接使用ThreadPoolExecutor提供的一些已经定制好的线程池,由Executors里的工厂方法创建。下面分析newSingleThreadExecutor、newFixedThreadPool、newCachedThreadPool的创建参数。
newFixedThreadPool
固定数量
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());}
newFixedThreadPool的corePoolSize和maximumPoolSize都设置为传入的固定数量,keepAliveTim设置为0。线程池创建后,线程数量将会固定不变,适合需要线程很稳定的场合。
newSingleThreadExecutor
串行
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));}
newSingleThreadExecutor是线程数量固定为1的newFixedThreadPool版本,保证池内的任务串行。注意到返回的是FinalizableDelegatedExecutorService,来看看源码:
static class FinalizableDelegatedExecutorService extends DelegatedExecutorService { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } protected void finalize() { super.shutdown(); }}
FinalizableDelegatedExecutorService继承了DelegatedExecutorService,仅仅在gc时增加关闭线程池的操作,再来看看DelegatedExecutorService的源码:
static class DelegatedExecutorService extends AbstractExecutorService { private final ExecutorService e; DelegatedExecutorService(ExecutorService executor) { e = executor; } public void execute(Runnable command) { e.execute(command); } public void shutdown() { e.shutdown(); } public List<Runnable> shutdownNow() { return e.shutdownNow(); } public boolean isShutdown() { return e.isShutdown(); } public boolean isTerminated() { return e.isTerminated(); } //...}
代码很简单,DelegatedExecutorService包装了ExecutorService,使其只暴露出ExecutorService的方法,因此不能再配置线程池的参数。本来,线程池创建的参数是可以调整的,ThreadPoolExecutor提供了set方法。使用newSingleThreadExecutor目的是生成单线程串行的线程池,如果还能配置线程池大小,那就没意思了。
Executors还提供了unconfigurableExecutorService方法,将普通线程池包装成不可配置的线程池。如果不想线程池被不明所以的后人修改,可以调用这个方法。
newCachedThreadPool
无限大
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
newCachedThreadPool生成一个会缓存的线程池,线程数量可以从0到Integer.MAX_VALUE,超时时间为1分钟。线程池用起来的效果是:如果有空闲线程,会复用线程;如果没有空闲线程,会新建线程;如果线程空闲超过1分钟,将会被回收。
newScheduledThreadPool
固定数量,周期性执行
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
一个可以按指定时间可周期性的执行的线程池
BlockingQueue等待队列
newCachedThreadPool的线程上限几乎等同于无限,但系统资源是有限的,任务的处理速度总有可能比不上任务的提交速度。因此,可以为ThreadPoolExecutor提供一个阻塞队列来保存因线程不足而等待的Runnable任务,这就是BlockingQueue。
JDK为BlockingQueue提供了几种实现方式,常用的有:
ArrayBlockingQueue:数组结构的阻塞队列
LinkedBlockingQueue:链表结构的阻塞队列
PriorityBlockingQueue:有优先级的阻塞队列
SynchronousQueue:不会存储元素的阻塞队列
newFixedThreadPool和newSingleThreadExecutor在默认情况下使用一个无界的LinkedBlockingQueue。但是有两个缺点:
1. 如果任务一直提交,但线程池又不能及时处理,等待队列将会无限制地加长
2. 系统资源总会有消耗殆尽
所以,推荐使用有界的等待队列,避免资源耗尽,当队列填满后,再来新任务,就要用到饱和策略来处理了。
饱和策略
ThreadPoolExecutor的饱和策略通过传入RejectedExecutionHandler来实现。如果没有为构造函数传入,将会使用默认的defaultHandler。
默认实现:AbortPolicy:
自己处理
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }}
AbortPolicy是默认的实现,直接抛出一个RejectedExecutionException异常,让调用者自己处理。
DiscardPolicy
后续的任务都抛弃掉
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { }}
DiscardPolicy的rejectedExecution直接是空方法,什么也不干。如果队列满了,后续的任务都抛弃掉。
DiscardOldestPolicy
等待队列里最旧的任务踢走,让新任务得以执行
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
DiscardOldestPolicy会将等待队列里最旧的任务踢走,让新任务得以执行。
CallerRunsPolicy
直接在当前线程运行这个任务
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
最后一种饱和策略是CallerRunsPolicy,它既不抛弃新任务,也不抛弃旧任务,而是直接在当前线程运行这个任务。当前线程一般就是主线程啊,让主线程运行任务,说不定就阻塞了。如果不是想清楚了整套方案,还是少用这种策略为妙。
ThreadFactory
每当线程池需要创建一个新线程,都是通过线程工厂获取。如果不为ThreadPoolExecutor设定一个线程工厂,就会使用默认的defaultThreadFactory:
public static ThreadFactory defaultThreadFactory() { return new DefaultThreadFactory();}
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
平时打印线程池里线程的name时,会输出形如pool-1-thread-1之类的名称,就是在这里设置的。这个默认的线程工厂,创建的线程是普通的非守护线程,如果需要定制,实现ThreadFactory后传给ThreadPoolExecutor即可。
参考文章
分析Java线程池的创建
Android线程与线程池
- Android线程池(二)构造方法的参数详细说明
- 线程的详细说明
- android笔记 SimpleAdapter的构造方法说明
- Android RectF类的构造函数参数说明
- Android RectF类的构造函数参数说明
- Android RectF类的构造函数参数说明
- Android Rect类的构造函数参数说明
- <Android>inflate的方法参数说明
- Java线程的详细说明
- FusionCharts参数的详细说明
- FusionCharts参数的详细说明
- FusionCharts参数的详细说明
- fusionCharts参数的详细说明
- static代码块,代码块 ,构造方法(一个参数),构造方法(二个参数)
- android 中RectF构造函数参数说明
- 关于构造方法的说明
- JAVA--构造方法的说明
- 构造方法的简单说明
- 【maven】9、pom.xml介绍(二)
- 订阅与发布的实现与应用
- POJ 3650 The Seven Percent Solution
- JavaScript学习-Array的方法
- Java并发编程艺术----读书笔记(三)
- Android线程池(二)构造方法的参数详细说明
- PKU 2366 Wireless Network
- HDU 1106 排序
- 关于java堆和栈的区别
- svn出现Authorization failed错误
- B. Weird Rounding
- Django generic.Views 源码初步剖析
- C++三种保护方式
- 图像拼接(十二):OpenCV SeamFinder+GraphCut+最佳拼接缝寻找