众所周知,显式创建,开启线程的方式:
new Thread( new RunnableTask() ).start();
这种方式,每次调用都会产生对象(java编程中产生对象,就要开辟内存空间)。当频繁调用线程时,这种方式开启线程会占很多的内存。
针对各种需求,优化内存,java 拥有更优雅的方式调用线程,即通过线程池来调用。
(一)Executor接口:
Executor是一个灵活的基于接口的任务执行工具,属于java.util.concurrent包中。
ExecutorService executor= Executors.newSingleThreadExecutor() ;
添加任务的方法:
executor.execute(runnable);
终止的方法:
shutdown():等待线程池中任务执行完后(期间不再接受新任务),再关闭
(二)ExecutorService接口:
特性:
ExecutorService接口 是Executor接口的子接口
api:
submit():提交一个 Runnable 任务用于执行
shutdown():等待线程池中任务执行完后(期间不再接受新任务),再关闭
shutdownNow():立刻关闭线程池,终止进行的任务,返回没有执行的任务
产生方式:
Executors一个线程池的工具类,里面含有静态工厂,产生不同需求的executor service,即针对不同需求的线程池
1.适合小程序的线程池:
ExecutorService pool = Executors.newCachedThreadPool();
特性:线程池中线程可重用,若是没有可用线程,创建新的线程(适合小程序)
缺点:添加的任务立马执行(若是没有缓存可用的线程,则创建新的线程),不存在任务队列,
若是执行的任务太多,会导致cpu被占据(大负载的服务器不适用)
2.适合大负载的服务器的线程池:
ExecutorService pool = Executors.newFixedThreadPool(int nThreads)
特性: 可重用,线程数量固定的线程池,以共享的无界队列方式来运行这些线程
(ps:若是更有效控制线程池,使用ThreadPoolExecutor)
(三)ScheduledExecutorService接口:
特性:
ScheduledExecutorService:一个定时周期任务的线程(首次可以延迟),ExecutorService的子接口
api:
schedule():
使用各种延迟创建任务,并返回一个可用于取消或检查执行的任务对象
scheduleAtFixedRate() 和 scheduleWithFixedDelay() :
创建并执行某些在取消前一直定期运行的任务。
好处:
用于替代java.utls.Timer
Timer+thread模式的缺点:
1.只能调用一个线程执行任务,对于周期性的任务,会导致定时不准确
2.当timer所对应的thread抛出异常时,线程停止。
ScheduledExecutorService的好处:支持多线程,从抛出异常的任务中恢复
使用方式:
// 定时任务
private ScheduledExecutorService scheduledExecutorService;
scheduledExecutorService =
//产生方式1:
Executors.newSingleThreadScheduledExecutor();
//产生方式2:
Executors. newScheduledThreadPool(1);
//开启线程方式:
scheduleAtFixedRate(Runnable command, long initialDelay,long period,TimeUnit unit)
//参数:执行的Runnable对象,首次延迟时间,周期(即每隔多久执行一次,时间单位)
使用场景:定时任务,如广告轮播图等
(四)ThreadPoolExecutor类:
特性:
ThreadPoolExecutor是一个ExecutorService的实现类,这个类允许你控制线程池操作的几乎每一个方面(推举使用)
使用方式:
ThreadPoolExecutor threadPool=ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler)
//参数:
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略
//执行runnable 对象:
threadPool.execute(runnable);
运用场景:android 加载图片的线程池 或者 普通功能的线程池 或者 联网功能的线程池
android官方案例:通过线程池加载图片(只涉及线程池配置)
// 获取cpu中允许的最大线程数
private static final int POOLSIZE = Runtime.getRuntime()
.availableProcessors();
private static final int keepAliveTime = 1;
private static final TimeUnit unit = TimeUnit.SECONDS;
private final BlockingQueue<Runnable> queue;
private final ThreadPoolExecutor threadPool;
queue = new LinkedBlockingQueue<Runnable>();
//配置线程池
threadPool = new ThreadPoolExecutor(POOLSIZE,
POOLSIZE,
keepAliveTime,
unit,
queue);
实际项目线程池使用,参考::android 高效加载bitmap
衍生点:
1.虽然官方封装了一个含有线程池+handler回调异步加载工具AsyncTask, 但是工作任务队列限制为128个,对于部分需求不能满足
2.android 更新UI : Handler+ExecutorService(线程池)+MessageQueue+缓存模式(针对AsyncTask的解决方式,推举使用)
3.对AsyncTask感兴趣的,可以阅读 AsyncTask介绍