传统线程的弊端
1.重复创建线程对象,性能差;
2.线程缺乏统一管理,可能会无限制创建新的线程,线程之间存在CPU资源竞争,导致CPU占用过高,或者发生OOM;
3.缺乏功能,例如定时。
线程池的好处
1.重用已存在的线程,减少对象的创建、销毁,性能佳
2.有效控制最大并发线程,提高资源使用率,避免过多资源竞争,避免堵塞;
3.提供定时执行、定期执行、单线程、并发控制等功能;
线程池的使用
1. newCacheThreadPoll (缓存线程池)
可以灵活回收无任务的线程,如果没有线程回收,则创建新的线程,实例如下
ExecutorService cacheThreadPoll = Executors.newCachedThreadPool(); //创建一个缓存线程池for (int i = 0; i < 20; i++) {final int index = i;//execute开启一个线程任务cacheThreadPoll.execute(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行任务 :" + index);}});}
运行代码结果如下:
分析log: 我们发现在20次线程任务中,实际被创建的线程只有12个,说明其中有一部分线程被复用了,为了更直观明显体验线程复用,对代码稍作修改
private void cacheThread() {ExecutorService cacheThreadPoll = Executors.newCachedThreadPool(); //创建一个缓存线程池for (int i = 0; i < 20; i++) {final int index = i;//execute开启一个线程任务cacheThreadPoll.execute(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行任务 :" + index);}});try {Thread.sleep(2000); //每次睡眠2s,直观看出线程复用效果} catch (InterruptedException e) {e.printStackTrace();}}}
运行结果如下:
这个时候观察log,发现20个线程任务,由统一的一个线程复用完成。
2. newFixedThreadPoll (定长线程池)
创建一个定长线程池,可控制最大线程并发数,超出的线程在队列中等待
private void fixedThread() {ExecutorService fixedThreadPoll = Executors.newFixedThreadPool(4); //创建一个缓存线程池for (int i = 0; i < 20; i++) {final int index = i;//execute开启一个线程任务fixedThreadPoll.execute(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行任务 :" + index);try {Thread.sleep(1000); //每次睡眠2s,直观看出线程复用效果} catch (InterruptedException e) {e.printStackTrace();}}});}}
运行结果如下:
发现线程每次并发4个任务
3. newSingleThreadEcutor (单例程池)
只会用唯一的一个工作线程去执行任务,保证所有任务按照指定顺序去执行。
ExecutorService singleThreadPoll = Executors.newSingleThreadExecutor(); //创建一个缓存线程池for (int i = 0; i < 20; i++) {final int index = i;//execute开启一个线程任务singleThreadPoll.execute(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行任务 :" + index);}});}
4. newScheduledThreadPool (定长线程池,支持定时,周期)
//创建一个缓存线程池,单一的,可以创建多个//第一种用法,延迟3秒执行ScheduledExecutorService schThreadPoll = Executors.newSingleThreadScheduledExecutor();Log.d(TAG, "开始执行3s任务 :");//定时3s后执行schThreadPoll.schedule(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行3s任务 :");}}, 3, TimeUnit.SECONDS);//第二种,周期性任务。4s后执行,每隔3s执行一次schThreadPoll.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {Log.d(TAG, Thread.currentThread().getName() + " 执行3s任务 :");}},4, 3, TimeUnit.SECONDS);schThreadPoll.shutdown(); // 停止周期任务