线程池的基本使用笔记

线程池的使用

首先当然要先说线程池的优点。

  1. 重用线程池中的线程,避免因线程的创建和销毁带来性能开销。
  2. 能有效控制线程池最大并发数,避免大量线程因互相抢占系统资源而阻塞
  3. 对线程进行简单管理,并提供定时执行以及制定间隔循环执行能力

ThreadPoolExecutor

构造方法

ThreadPoolExcutor是线程池的实现,其实现了ExecutorService接口,并在构造方法中设置了各种参数

public ThreadPoolExecutor(int corePoolSize, 
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue<Runnable> workQueue,
                        ThreadFactory threadFactory)

这里一一介绍一下这些参数

corePoolSize

是线程的核心线程数。所谓核心线程是指在线程池中常驻的线程。该类线程即使闲置也不会被回收。因此可以被快速调用。(如果allowCoreThreadTimeOut属性设置为true则在超时后也会被终止)

maximumPoolSize

最大线程数,当线程数超过corePoolSize时会开始创建临时线程,而总线程数超过maximumPoolSize时新任务则会被阻塞。

keepAliveTime

非核心线程闲置时间,超过这个时间,则非核心线程会被回收。

unit

用于指定keepAliveTime的单位,是个枚举类。常用的是TimeUnit.MILLISECONDS、TimeUnit.SECONDS、TimeUnit.MINUTES等
应导入java.util.concurrent.TimeUnit

workQueue

任务队列,通过execute方法提交的Runnable会储存在队列里。可以设置最大数

threadFactory

县城工厂,为线程池提供创建新线程的功能。ThreadFactor是个接口,有一个方法:Thread newThread(Runnable r)

任务规则
  1. 若线程池的线程未达到核心线程数量,则直接启动一个核心线程执行任务
  2. 若线程池中的线程数已经达到或超过核心线程数,则任务被插入到任务队列中排队执行
  3. 如果在2中无法将任务插入任务队列,则往往是由于队列已经满了。这时候如果线程数量未达到线程池最大值,则立刻启动一个非核心线程
  4. 若3中线程数量已经达到规定最大值,则拒绝执行
AsyncTask中的线程池

AsyncTask内部是使用线程池来实现功能的。其配置参数如下:

  • 核心线程数为CPU核心数+1
Runtime.getRuntime().avaliableProcessors() + 1;
  • 线程池最大线程数为CPU核心数的2倍 + 1
Runtime.getRuntime().avaliableProcessors() * 2 + 1;
  • 核心线程无超时机制,非核心线程限制时间为1s
int keepAlive = 1;
unit = TimeUnit.SCEONDS;
  • 任务队列容量为128
new LinkedBlockingQueue<Runnable>(128);

用Executors创建线程池

线程池分类

用Executors创建的线程池分4类,首先作为测试的代码如下:

主线程

        while (true) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            StringBuilder sb = new StringBuilder()
                    .append("\n1:").append(runnable1.value)
                    .append("\n2:").append(runnable2.value)
                    .append("\n3:").append(runnable3.value)
                    .append("\n4:").append(runnable4.value)
                    .append("\n5:").append(runnable5.value);
            Log.d("RUNNABLE", sb.toString());
        }

测试线程

    private class TestRunnable implements Runnable{
        private int value;

        @Override
        public void run() {
            while (true) {
                value += 10;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (value > 160)
                    break;
            }
        }
    }
FixedThreadPool

该线程池是一种线程数固定的线程池,其核心线程数即为总核心数,除非线程池关闭,否则所有线程都处于活动状态。同时其任务对列也没有限制

获取方法内部:

    public static ExecutorService newFixedThreadPool(int         nThreads){
        return new ThreadPoolExecutor
                (nThreads, nThreads, 0L, TimeUnit.MILLISECONDS
                        ,new LinkedBlockingQueue<Runnable>());
    }

测试内容:

        int threadCount = 3;
        //静态线程池,固定线程数,不会被回收
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(threadCount);
        
        fixedThreadPool.execute(runnable1);
        fixedThreadPool.execute(runnable2);
        fixedThreadPool.execute(runnable3);
        fixedThreadPool.execute(runnable4);
        fixedThreadPool.execute(runnable5);

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Bsdwodw-1592182056018)(http://m.qpic.cn/psb?/V10DRhHC2m1DNs/RqKq9j7tj7TQkwVJPpsgzvIK8g0UiZyzrOf67pUMNh8!/b/dDMBAAAAAAAA&bo=QwF9AgAAAAADBx8!&rf=viewer_4)]

CachedThreadPool

该线程池是一种线程数量不确定的线程池。其只有非和新线程,切最大线程数为Integer.MAX_VALUE。相当于没有限制。当线程池中的线程都出于活动时,线程池会创建新的线程来处理新任务。否则会用空闲的线程来处理任务。该线程池的超时市场为60s。其任务队列为一个空基和,是无法插入任何任务。因此所有的人物都将立刻执行。

当无任务时,该线程池内没有任何线程,因此是不占用任何资源的。

方法如下:

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

测试代码:

        //临时线程池,最大线程数为Integer.MAX_VALUE, 所有任务立即执行,适合执行大量耗时较少的任务。没有核心线程
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        
        cachedThreadPool.execute(runnable1);
        cachedThreadPool.execute(runnable2);
        cachedThreadPool.execute(runnable3);
        cachedThreadPool.execute(runnable4);
        cachedThreadPool.execute(runnable5);

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mAP9huK9-1592182056023)(http://m.qpic.cn/psb?/V10DRhHC2m1DNs/JTVColnmdnmfQ5sJpxfEkNpVpJ8H4JY3huiImeHh0!/b/dIMAAAAAAAAA&bo=0QB4AgAAAAADB4k!&rf=viewer_4)]

ScheduledThreadPool

该线程池核心线程数是固定的,而非核心线程数没有限制。当非和新线程闲置时会被立即回收。这类线程池主要用于执行定时任务和具有固定周期的重复任务。

方法如下:

    public static ScheduledExecutorService newCachedThreadPool(){
        return new ScheduledThreadPoolExecutor
                (0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS
                        ,new SynchronousQueue<Runnable>());
    }
    
    public ScheduledThreadPoolExecutro(int corePoolSize){
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS
                ,new DelayedWorkQueue());
    }

用法如下:

        //2000ms 后执行
        scheduledThreadPool.schedule(runnable1, 2000, TimeUnit.MILLISECONDS);
        //延迟10ms后,每1000ms执行一次
        scheduledThreadPool.scheduleAtFixedRate(runnable1, 10, 1000, TimeUnit.MILLISECONDS);
SingleThreadExecutor

该线程池内只有一个核心线程,其确保所有的人物都在同一个线程内按顺序执行。其意义在于统一所有外界任务到一个线程中。使得这些任务不需要处理线程同步的问题。

方法如下:

    public static ExecutorService newSingleThreadExecutor(){
        return new FinalizableDelegatedExecutorServce
                (new ThreadPoolExecutor(1,1
                        ,0L,TimeUnit.MILLISECONDS
                        ,new LinkedBlockingQueue<Runnable>()));
    }

用法与前两种相同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值