Android线程优化之线程池的详解

本文授权发布公众号【刘桂林】,星球【Hi Android】

ThreadPoolExecutor还是有很多可讲的,但是我选择的还是着重讲解Android中的四个线程池,网上对ThreadPoolExecutor的例子太多了,也比较杂,大家可以去看看。

Android中的线程池的概念来源于Java中的Executor,Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor,其中所实现的四个线程池每一个的作用都是不一样的,我们一起来看下:

FixThreadPool
FixThreadPool通过如下代码实现:

ExecutorService service = Executors.newFixedThreadPool(5);
Runnable r = new Runnable() {
    @Override
    public void run() {
        Log.i(TAG, "newFixedThreadPool");
    }
};
service.execute(r);

队列线程池,因为核心线程池是固定的,所以不管你如何execute,都会一个个来执行完成,因为直接创建使用,没有回收,所以他的优势是响应速度很快,效率更高。

这里我们可以模拟一下:

ExecutorService service = Executors.newFixedThreadPool(2);

for (int i = 0; i < 10; i++) {
    final int finalI = i;
    service.execute(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                Log.i(TAG, "newFixedThreadPool:" + finalI );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

这里指定核心线程数为2,然后执行10个任务,得到的结果:


可以看出,首先他是无序的,其次他每隔两秒钟打印两个,也就验证了刚才的说法,他线程数满了之后需要等待,就是排队打饭一样。

SingleThreadPool
顾名思义,这个都不需要指定核心线程数,代码如下:

ExecutorService service = Executors.newSingleThreadExecutor();
Runnable r = new Runnable() {
    @Override
    public void run() {
        Log.i(TAG, "newSingleThreadExecutor");
    }
};
service.execute(r);

这个其实和newFixedThreadPool(1)是一样的,SingleThreadPool主要还是为了线程同步而来的,newFixedThreadPool可以同时执行多任务,所以肯定不是同步的,如果什么场景需要线程同步,那SingleThreadPool再合适不过了。

如果我们把上面的例子改成SingleThreadPool:

ExecutorService service = Executors.newSingleThreadExecutor();

for (int i = 0; i < 10; i++) {
    final int finalI = i;
    service.execute(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                Log.i(TAG, "newSingleThreadExecutor:" + finalI );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

可以得到的结论:首先他是有序的,其次他每隔两秒则打印一次,而Log的输出也刚好验证了我的结论:

CachedThreadPool
CachedThreadPool还是比较多使用的,他不需要指定线程数,因为他的线程数很大,但是不存在核心线程,这也就意味着经常被回收,他的回收思路是,执行任务,任务结束后,保留60s,在60s来了新任务则继续使用刚才的线程,如果60s内无任务则回收线程,有点类似吃饭,你去盛饭没关系,但是你吃完走了我就要收盘子,间隙就在60s

ExecutorService service = Executors.newCachedThreadPool();
Runnable r = new Runnable() {
    @Override
    public void run() {
        Log.i(TAG, "newCachedThreadPool");
    }
};
service.execute(r);

我们继续改造我们的示例代码:

ExecutorService service = Executors.newCachedThreadPool();

for (int i = 0; i < 10; i++) {
    final int finalI = i;
    service.execute(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                Log.i(TAG, "newCachedThreadPool:" + finalI );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

这段代码在前面两个线程池都使用到了,就是用来告诉你他们的区别,我们使用newCachedThreadPool执行后得到的结果:

看Log,我们得到的结论是:首先他也是无序的,并且他因为子线程够多,所以sleep两秒后直接全部打印出来了。

ScheduledThreadPool
这是一个可操作性较强的线程池,也是唯一一个可循环的线程池,便于一些重复性的工作使用

ScheduledExecutorService service = Executors. newScheduledThreadPool (5);
Runnable r = new Runnable() {
    @Override
    public void run() {
        Log.i(TAG, "newScheduledThreadPool");
    }
};
Log.i(TAG,"start");
service.scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);

scheduleAtFixedRate中有四个参数,第一个是任务,第二个是延时时长,第三个是循环时长,第四个是单位,也就是说,当启动scheduleAtFixedRate之后,在1s后才开始执行这个间隔2s的任务不断循环,可以这样理解,启动任务后,这里延时1s,然后才开始执行任务,以后每隔2s重复执行

我们拿着示例继续改造:

ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

for (int i = 0; i < 10; i++) {
    final int finalI = i;
    service.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                Log.i(TAG, "newCachedThreadPool:" + finalI );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    },1000,2000,TimeUnit.MILLISECONDS);
}

这段代码比上面的复杂一些,我们看打印:

这里得到的是什么结论呢?比较多,首先,他是无序的,其次他间隔2s无限重复,并且启动这个县城需要3s,也就是延迟的1s + sleep的3s。

到这里我相信大家还是比较清晰的认知线程池,但是线程池是结合实战的,不然的话也都是纸上谈兵,但是一般线程池也只是替换new Thread的操作,所以示例的话,大家可以自行寻找一下,后续的实战项目文章,我再带领大家学习线程池。

有兴趣可以加入我的星球:Hi Android , 里面可都是我手撸的新鲜文章,高质量你值得拥有!

进入星球你可以做什么?

1.我的所有视频可以观看
2.发布提问贴可以得到满意的答案
3.可指定我写你感兴趣的技术文章
4.初学者可配套视频辅导
5.有机会线下交流聚会

©️2020 CSDN 皮肤主题: 成长之路 设计师: Amelia_0503 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值