Android线程池(二)构造方法的参数详细说明

来源:互联网 发布:腾讯云免费域名 编辑:程序博客网 时间:2024/06/14 12:19

构造方法

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线程与线程池

0 0
原创粉丝点击