JAVA线程池分为以下几种
- newCachedThreadPool
- newFixedThreadPool
- newSingleThreadExecutor
- newScheduledThreadPool
- 总结

首先我们先来想一下我们平常都是怎样创建的:

匿名类的创建

new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();

这样来看普通创建是存在弊端的(下面会结合代码说明)

  1. 每次new Thread 新创建对象的性能差
  2. 线程缺乏统一管理,可能无限制的新建线程,相互之间竞争,可能会占用过多的系统资源导致OOM
  3. 缺乏更多的功能,比如定时执行,定期执行,线程中断

线程池的好处
1. 重用存在的线程,减少对象的创建,消亡的开销,性能佳
2. 可有效控制最大并发的线程数,提高系统资源使用率,避免过多竞争,避免堵塞
3. 提供定时执行,定期执行,单线程,并发数控制等功能

下面就是怎么使用线程池

所有的案例我们都是使用for循环创建了10个任务,有的任务是耗时的有的是不耗时的

new Thread

这个就不用过多的解释了。。。。。。

代码:

for(int i=0;i<10;i++){
            final int index=i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG","new Thread:"+"\n"+"name:"+Thread.currentThread().
                            getName()+"\n"+"i:"+index);
                }
            }).start();
        }

打印日志:

Android Rxjava线程池数量 android线程池有几种_线程池

  

Android Rxjava线程池数量 android线程池有几种_打印日志_02

  

Android Rxjava线程池数量 android线程池有几种_android_03

可以看出每一个Thread的name 都是不一样的,这样可不就创建了很多个对象了吗,造成资源浪费

newCachThreadPoll

简介:创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收,继续创建新的线程

代码:

//所有的都是ExecutorService的一个对象
        ExecutorService cacheThreadPoll= Executors.newCachedThreadPool();
        //创建10个子线程的任务
        for (int i=0;i<10;i++){
            //i在下面取不到,赋值给index
            final int index=i;
            //每执行一次任务就休息两秒钟
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            cacheThreadPoll.execute(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG","cacheThreadPoll"+"\n"+"name:"+Thread.currentThread().
                            getName()+"\n"+"i:"+index);
                }
            });
        }

打印日志:

Android Rxjava线程池数量 android线程池有几种_线程池_04

  

Android Rxjava线程池数量 android线程池有几种_打印日志_05

  

Android Rxjava线程池数量 android线程池有几种_Android Rxjava线程池数量_06

这些线程的名字都是一样的,也就是说只创建了一个对象,就避免了资源的浪费

那么当第一个任务还没执行完,没有空闲的线程对象可以使用了会怎么办呢,我们就可以模拟一下(把休眠去掉即可)  

Android Rxjava线程池数量 android线程池有几种_Android Rxjava线程池数量_07

  

Android Rxjava线程池数量 android线程池有几种_线程池_08

  

Android Rxjava线程池数量 android线程池有几种_线程池_09

可以看出来这个线程池中创建了5个线程对象,有的线程对象被使用了多次,并且i的打印顺序不对,那为什么我们停止休眠操作后会出现这个问题呢

i的执行顺序:

CPU在处理子线程任务的时候是随机的,也是穿插执行的,我们同时并发了10个子线程0123…9,因为没有睡眠,所以这些子线程几乎是同时执行,它在执行的时候会随机执行,并且可能会在1上执行一点然后又去2执行,2还没执行完又回到1执行了,所以就造成了i的打印不是顺序的

线程池开启了5个子线程:

当前1号线程被占用,所以只能再开启2号线程去执行其他任务了,当1号线程执行完它的任务之后,它会看看哪些任务还是没有执行的,再去执行其他的任务,最后2号执行完任务并发现没有别的任务了,2号就被回收了

newFixedThreadPool

简介:创建一个定长线程池,可控制线程最大的并发数,超出线程会在队列中等待
代码:

//定义线程池的大小为3
        ExecutorService fixedThreadPool=Executors.newFixedThreadPool(3);
        for (int i=0;i<10;i++){
            final int index=i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG","fixedThreadPool:"+"\n"+"name:"+Thread.currentThread().
                            getName()+"\n"+"i:"+index);
                }
            });
        }

打印日志:

Android Rxjava线程池数量 android线程池有几种_Android Rxjava线程池数量_10

  

Android Rxjava线程池数量 android线程池有几种_线程池_11

  

Android Rxjava线程池数量 android线程池有几种_Android Rxjava线程池数量_12

和上面不同,这里不管有几个任务并发,只会有3个线程对象去执行任务,其他的任务只能等着了~

newSingleThreadExecutor

简介:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO)优先执行

代码:

//创建一个单一线程池
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG", "singleThreadPool:" + "\n" + "name:" + Thread.currentThread().
                            getName() + "\n" + "i:" + index);
                }
            });
        }

打印日志:

Android Rxjava线程池数量 android线程池有几种_Android Rxjava线程池数量_13

  

Android Rxjava线程池数量 android线程池有几种_ide_14

  

Android Rxjava线程池数量 android线程池有几种_ide_15

不管我们的任务有多少,我们的线程对象只会开启一个

newScheduledThreadPool

简介:创建一个定长的线程池,支持定时及周期性任务的执行,比如两秒之后想做什么,或者是每两秒想做什么

定时执行:

//得到当前毫秒数
        Log.e("TAG", "textScheduled start:"+System.currentTimeMillis());
        //创建一个定长的线程池,并且里面的线程对象都是单一的
        ScheduledExecutorService scheduledExecutorService = Executors.
                newSingleThreadScheduledExecutor();
        //定义3秒之后执行什么
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                //三秒钟之后会执行到打印Log这一步
                Log.e("TAG", "delay 3 seconds:"+System.currentTimeMillis());
            }

打印日志:

Android Rxjava线程池数量 android线程池有几种_ide_16

中间是相差三秒钟的,并且这个线程只执行了一次

周期性的执行:

//周期性执行任务,2秒后执行,每隔3秒执行一次
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            //控制执行次数的变量
            @Override
            public void run() {
                Log.e("TAG", "delay 2 seconds,and execute every 3seconds");
            }
        }, 2, 3, TimeUnit.SECONDS);

打印日志:

Android Rxjava线程池数量 android线程池有几种_线程池_17

从textScheduled start 到下面的delay…..的带引中间相差了2s,然后每个delay……之间的打印中间相差了3s而且是一直打印下去

停止周期循环:

scheduledExecutorService.shutdown();

总结

不难看出他们之间的使用是有一些规律的

  1. 创建对象——— Executors.newXXXXExecutor( ) ;创建出一个 ExecutorService 的对象,当然 ScheduledExecutorService 是 newScheduledThreadPool 的对象
  2. 将任务放置到线程池———xxxx.execute,参数传递的是一个Runnable接口(newScheduledThreadPool 例外 )