JAVA线程池实现类ThreadPoolExecutor分析

线程池的优点:
1、重用线程池的线程,减少线程创建和销毁带来的性能开销
2、控制线程池的最大并发数,避免大量线程互相抢系统资源导致阻塞
3、提供定时执行和间隔循环执行功能

Android中的线程池的概念来源于Java中的Executor, Executor是一个接口, 真正的线程池的实现为ThreadPoolExecutor.Android的线程池 大部分都是通 过Executor提供的工厂方法创建的。

ThreadPlloExecutor

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方法来通知调用者.。

线程池的分类

(1)FixedThreadPool: 定长线程池

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();
					}	
				 }
			});	
		}
	}
}

输出结果
JAVA线程池实现类ThreadPoolExecutor分析_第1张图片
由于设置最大线程是5,所以当执行完这5个线程后,等待两秒后,在执行后面2个线程

(2)CachedThreadPool: 可缓存线程池

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()); 
				}
			});	
		}
	}
}

输出结果:
JAVA线程池实现类ThreadPoolExecutor分析_第2张图片
从结果可以看到,执行第二个任务的时候第一个任务已经完成,会复用执行第一个任务的线程,不用每次新建线程。

(3)ScheduledThreadPool: 定长线程池

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秒执行
	}
}

输出结果
JAVA线程池实现类ThreadPoolExecutor分析_第3张图片
实际结果确实延迟了约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秒执行一次
	}
}

输出结果
JAVA线程池实现类ThreadPoolExecutor分析_第4张图片
可发现确实延迟2秒后每隔3秒后就会执行一次,程序不退出就一直执行下去

(4)SingleThreadExecutor: 单线程化的线程池

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();
					}	
				}
			});	
        }
	}
}

输出结果:
JAVA线程池实现类ThreadPoolExecutor分析_第5张图片
可发现是有顺序地去执行上面6个线程。

参考文章有Android开发艺术探索和真·深红骑士的java线程池介绍

你可能感兴趣的:(进阶类)