Android线程池理解

为什么使用线程池

当我们需要频繁地创建多个线程进行耗时操作时,每次都通过new Thread实现并不是一种好 的方式,每次new Thread新建和销毁对象性能较差,线程缺乏统一管理,可能无限制新建线程, 相互之间竞争,可能占用过多系统资源导致死锁,并且缺乏定时执行、定期执行、线程中断等功能。 好在Java提供了 4种线程池,它能够有效地管理、调度线程,避免过多的资源消耗,它强大到几 乎不需要幵发人员自定义的程度。它的优点如下:
  (1)    重用存在的线程,减少对象创建、销毁的幵销;
  (2)    可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞;
  (3)    提供定时执行、定期执行、单线程、并发数控制等功能。
线程池原理简单地解释就是会创建多个线程并且进行管理,提交给线程的任务会被线程池指派给 其中的线程进行执行,通过线程池的统一调度、管理使得多线程的使用更简单、高效。如下图所示。

 

基本的线程池 ThreadPoolExecutor

它的功能是启动指定数量的线程以及将任务添加到一个队列中,并且将任务分发给空闲的线程。ExecutorService 的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用的 shutdown() 方法时,便进入关闭状态,此时意味着 ExecutorService 不再接受新的任务,但它还在执行已提交的任务。当所有已提交的任务执行完后,就变成终止状态。

ThreadPoolExecutor 的构造函数如下:

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

下面对这几个参数详细说明:

ThreadPoolExecutor 的使用流程:

        /**
         * 1.创建基本线程池
         * corePoolSize:该线程池中核心线程的数量。
         * maximumPoolSize:最大线程数量
         * keepAliveTime:非核心线程空闲时要等待下一个任务到来的时间
         * unit:上面时间属性的单位
         * workQueue:任务队列
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                3, 
                5, 
                1, 
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(100));

        /**
         * 2. 向线程池提交任务:execute()
         */
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                // 线程执行任务
            }
        });

        /**
         * 3. 关闭线程池shutdown()
         * 也可调用shutdownNow()关闭线程:threadPool.shutdownNow()
         * shutdown:设置 线程池的状态 为 SHUTDOWN,然后中断所有没有正在执行任务的线程
         * shutdownNow:设置 线程池的状态 为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
         * 使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow()
         */
        threadPool.shutdown();

上面介绍的是基本的线程池 ThreadPoolExecutor 简单介绍,但这个并不是常用的;后面会介绍几种常用的线程池,它们都是根据 ThreadPoolExecutor 的基础上延伸的。

 

常用的线程池

启动指定数量的线程池 - FixedThreadPool

定时执行一些任务的线程池 - ScheduledThreadPool

可缓存的线程池 - CachedThreadPool

单个核线的线程池 - SingleThreadExecutor

 

这里面最常用的线程池是 FixedThreadPool ,下面来分别看一下它们的基本使用

 

启动指定数量的线程池 - FixedThreadPool

特点:该线程池只有核心线程,不会被回收;一般用于控制线程的最大并发数

    //创建线程池
    public ExecutorService mExecutor = Executors.newFixedThreadPool(5);

    //创建线程对象
    public class MyRunnable implements Runnable {

        private final int width;
        private final int height;

        public MyRunnable(int imageWidth, int imageHeight) {
            this.width = imageWidth;
            this.height = imageHeight;
        }

        @Override
        public void run() {
            //逻辑处理
            if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
                Log.e("wqs", "主线程: " + Thread.currentThread().getName());
            } else {
                Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
            }
        }
    }

    //向线程池添加任务
    private synchronized void startRunnable() {
        mExecutor.execute(new MyRunnable(100, 100));
    }

    //关闭线程池
    private void stopExecutor(){
        mExecutor.shutdown();
    }

当我们一直调用上面的 startRunnable() 方法时,可以看出最多有五个线程来处理我们的任务,如下图:

 

定时执行一些任务的线程池 - ScheduledThreadPool

特点:核心线程数量一定,非核心线程数量多个,闲置时会立马回收非核心线程数量;一般用于定时的任务

    //创建线程池
    public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

    //创建线程对象
    public class MyRunnable implements Runnable {

        private final int width;
        private final int height;

        public MyRunnable(int imageWidth, int imageHeight) {
            this.width = imageWidth;
            this.height = imageHeight;
        }

        @Override
        public void run() {
            //逻辑处理
            if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
                Log.e("wqs", "主线程: " + Thread.currentThread().getName());
            } else {
                Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
            }
        }
    }

    //延迟开始执行
    private synchronized void startRunnable() {
        //延迟1s后执行任务
        scheduledExecutorService.schedule(new MyRunnable(100, 100), 1, TimeUnit.SECONDS);
    }

    //延迟开始执行循环任务
    private synchronized void startRunnableCycle() {
        //延迟100ms后、每隔1000ms执行任务
        scheduledExecutorService.scheduleAtFixedRate(new MyRunnable(100, 100),100,1000,TimeUnit.MILLISECONDS);

    }

    //关闭线程池
    private void stopExecutor(){
        scheduledExecutorService.shutdown();
    }

 

可缓存的线程池 - CachedThreadPool

特点:只有非核心线程,线程数量不固定;一般用于执行大量耗时少的任务

    //创建线程池
    public ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

    //创建线程对象
    public class MyRunnable implements Runnable {

        private final int width;
        private final int height;

        public MyRunnable(int imageWidth, int imageHeight) {
            this.width = imageWidth;
            this.height = imageHeight;
        }

        @Override
        public void run() {
            //逻辑处理
            if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
                Log.e("wqs", "主线程: " + Thread.currentThread().getName());
            } else {
                Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
            }
        }
    }

    //开始执行
    private synchronized void startRunnable() {
        cachedThreadPool.execute(new MyRunnable(100, 100));
    }

    //关闭线程池
    private void stopExecutor(){
        cachedThreadPool.shutdown();
    }

 

单个核线的线程池 - SingleThreadExecutor

特点:只有一个核心线程(是一个单线程);一般用于数据库操作

    //创建线程池
    public ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

    //创建线程对象
    public class MyRunnable implements Runnable {

        private final int width;
        private final int height;

        public MyRunnable(int imageWidth, int imageHeight) {
            this.width = imageWidth;
            this.height = imageHeight;
        }

        @Override
        public void run() {
            //逻辑处理
            if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
                Log.e("wqs", "主线程: " + Thread.currentThread().getName());
            } else {
                Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
            }
        }
    }

    //开始执行
    private synchronized void startRunnable() {
        singleThreadExecutor.execute(new MyRunnable(100, 100));
    }

    //关闭线程池
    private void stopExecutor(){
        singleThreadExecutor.shutdown();
    }

 

上面是对线程池的简单理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值