线程池的优点:
1、重用线程池的线程,减少线程创建和销毁带来的性能开销
2、控制线程池的最大并发数,避免大量线程互相抢系统资源导致阻塞
3、提供定时执行和间隔循环执行功能
Android中的线程池的概念来源于Java中的Executor, Executor是一个接口, 真正的线程池的实现为ThreadPoolExecutor.Android的线程池 大部分都是通 过Executor提供的工厂方法创建的。
ThreadPoolExecutor是线程池的真正实现, 它的构造方法提供了一系列参数来配置线程池, 这些参数将会直接影响到线程池的功能特性.。下面是ThreadPoolExecutor常用的构造方法。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory);
}
corePoolSize: 线程池的核心线程数, 默认情况下, 核心线程会在线程池中一直存活, 即使都处于闲置状态. 如果将ThreadPoolExecutor#allowCoreThreadTimeOut属性设置为true, 那么闲置的核心线程在等待新任务到来时会有超时的策略, 这个时间间隔由keepAliveTime属性来决定. 当等待时间超过了keepAliveTime设定的值那么核心线程将会终止.
maximumPoolSize: 线程池所能容纳的最大线程数, 当活动线程数达到这个数值之后, 后续的任务将会被阻塞.
keepAliveTime: 非核心线程闲置的超时时长, 超过这个时长, 非核心线程就会被回收.
unit: 用于指定keepAliveTime参数的时间单位, 这是一个枚举
workQueue: 线程池中的任务队列, 通过线程池的execute方法提交的Runnable对象会存储参数中.
.
threadFactory: 线程工厂, 为线程池提供创建新线程的功能. ThreadFactory是一个接口.
ThreadPoolExecutor执行任务遵循如下规则:
1、如果线程池中的线程数量未达到核心线程的数量, 那么会直接启动一个核心线程来执行任务。
2、如果线程池中的线程数量已经达到或者超过核心线程的数量, 任务会被插入到队列中排队等待
3、如果在步骤2中无法将任务插入到任务队列中, 这通常是因为任务队列已满, 这个时候如果线程数量未达到线程池的规定的最大值, 那么会立刻启动一个非核心线程来执行任务.
4、如果步骤3中的线程数量已经达到最大值的时候, 那么会拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecution方法来通知调用者.。
newFixedThreadPool()方法来创建. 线程数量固定的线程池, 当线程处于空闲状态时, 并不会被回收, 除非线程池关闭了. 当所有的线程都处于活动状态时, 新任务都会处于等待状态, 直到有线程空闲出来. 由于FixedThreadPool只有核心线程并且这些核心线程不会被回收, 意味它能更快响应外界请求。
代码如下:
public class PoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
//设置最大线程数5个
ExecutorService mFixedThreadPool = Executors.newFixedThreadPool(5);
for(int i = 0;i < 7;i++ ) {
final int index = i;
mFixedThreadPool.execute(new Runnable() {
public void run() {
System.out.println("时间是:"+System.currentTimeMillis()+"第" +index +"个线程" +Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
输出结果
由于设置最大线程是5,所以当执行完这5个线程后,等待两秒后,在执行后面2个线程
newCachedThreadPool()方法来创建. 它是一种线程数量不定的线程池, 它只有非核心线程, 并且其最大值线程数为Integer.MAX_VALUE. 当线程池中的线程都处于活动的时候, 线程池会创建新的线程来处理新任务, 否则就会利用空闲的线程来处理新任务. 线程池中的空闲线程都有超时机制, 这个超时时长为60S, 超过这个时间那么空闲线程就会被回收.
和FixedThreadPool不同的是, CachedThreadPool的任务队列其实相当于一个空集合, 这将导致任何任务都会立即被执行, 因为在这种场景下SynchronousQueue是无法插入任务的. 在实际使用中这类线程比较适合执行大量的耗时较少的任务
代码如下:
public class PoolExecutorTest {
public static void main(String[] args) {
ExecutorService mCachelThreadPool = Executors.newCachedThreadPool();
for(int i = 0;i < 7;i++ ) {
final int index = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mCachelThreadPool.execute(new Runnable() {
public void run() {
System.out.println("第" +index +"个线程" +Thread.currentThread().getName());
}
});
}
}
}
输出结果:
从结果可以看到,执行第二个任务的时候第一个任务已经完成,会复用执行第一个任务的线程,不用每次新建线程。
newScheduledThreadPool()方法来创建. 它的核心线程数量是固定的, 而非核心线程数是没有限制的, 并且当非核心线程闲置时会立刻被回收掉. 这类线程池用于执行定时任务和具有固定周期的重复任务
延迟执行实例代码:
public class PoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
//设置池中核心数量是2
ScheduledExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("现在的时间:"+System.currentTimeMillis());
mScheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("现在的时间:"+System.currentTimeMillis());
}
}, 4, TimeUnit.SECONDS);//这里设置延迟4秒执行
}
}
定期执行示例代码:
public class PoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
//设置池中核心数量是2
ScheduledExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("现在的时间:"+System.currentTimeMillis());
mScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("现在的时间:"+System.currentTimeMillis());
}
}, 2, 3,TimeUnit.SECONDS);//这里设置延迟2秒后每3秒执行一次
}
}
输出结果
可发现确实延迟2秒后每隔3秒后就会执行一次,程序不退出就一直执行下去
newSingleThreadPool()方法来创建. 这类线程池内部只有一个核心线程, 它确保所有的任务都在同一个线程中按顺序执行. 这类线程池意义在于统一所有的外界任务到一个线程中, 这使得在这些任务之间不需要处理线程同步的问题。
代码如下:
public class PoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService mSingleThreadPool = Executors.newSingleThreadExecutor();
for(int i = 0;i < 7;i++) {
final int number = i;
mSingleThreadPool.execute(new Runnable() {
public void run() {
System.out.println("现在的时间:"+System.currentTimeMillis()+"第"+number+"个线程");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
参考文章有Android开发艺术探索和真·深红骑士的java线程池介绍