1 前言
android开发,大家最熟悉的肯定是主线程,也就是ui线程,也都知道在非ui线程更新界面会报错提示不允许在子线程更新ui。但是耗时操作还是需要使用子线程,如:
new Thread(new Runnable() {
@Override
public void run() {
// 耗时任务
}
}).start();
这种写法感觉简单便捷,但是在存在很大的弊端
1 如果某个地方需要开启大量的线程。创建线程和销毁线程是需要时间的,这样会导致性能不足
2 线程无法管理,相互竞争导致卡顿或者oom
3 功能太过单一
2 线程池
针对以上问题,提出线程池
1 重用存在的线程,减少对象创建、消亡的开销,性能佳
2 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
3 提供定时执行、定期执行、单线程、并发数控制等功能
3 官方提供了几种默认的线程池
newFixedThreadPool() | 该方法返回一个固定线程数量的线程池,该线程池中的线程数量始终不变,即不会再创建新的线程,也不会销毁已经创建好的线程,自始自终都是那几个固定的线程在工作,所以该线程池可以控制线程的最大并发数。 超出的线程会在队列中等待 |
newCachedThreadPool() | 该方法返回一个可以根据实际情况调整线程池中线程的数量的线程池。如果没有线程不够用则会一直创建,有空闲线程则会复用。 |
newSingleThreadExecutor() | 顾名思义,返回只有一个线程的线程池。多余的任务会存在队列中等待执行 |
newScheduledThreadPool() | 返回一个可以固定线程个数和设置线程延迟执行时间,执行周期 的线程池 |
//该线程池默认创建了3 个线程
ExecutorService lExecutorService = Executors.newFixedThreadPool(3);
//添加10个任务
for (int lI = 0; lI < 10; lI++) {
lExecutorService.execute(new Runnable() {
@Override
public void run() {
//异步任务
}
});
}
ScheduledExecutorService lExecutorService = Executors.newSingleThreadScheduledExecutor();
//延迟1秒后执行第一次任务,之后每隔1秒执行一次
lExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//异步任务
}
},1,2,TimeUnit.SECONDS);
ScheduledExecutorService lExecutorService = Executors.newSingleThreadScheduledExecutor();
for (int lI = 0; lI < 10; lI++) {
//每个任务被延迟1秒执行一次
lExecutorService.schedule(new Runnable() {
@Override
public void run() {
//异步任务
}
}, 1, TimeUnit.SECONDS);
}
}
4 自定义线程池
public class CustomExpanThreadPool extends ThreadPoolExecutor {
private CustomExpanThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public static CustomExpanThreadPool getInstance() {
//获取CPU数量
int processors = Runtime.getRuntime().availableProcessors();
//核心线程数量
int corePoolSize = processors + 1;
//最大线程数量
int maximumPoolSize = processors * 2 + 1;
//空闲有效时间
long keepAliveTime = 60;
//创建自定义线程池
return new CustomExpanThreadPool(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new PriorityBlockingQueue());
}
/**
* 用于控制线程开始与停止执行的方法
*/
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
/**
* 任务执行前要执行的方法
*
* @param t
* @param r
*/
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
System.out.println(Thread.currentThread().getName() + " 任务执行开始 ");
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
}
}
/**
* 任务执行后要执行的方法
*
* @param r
* @param t
*/
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
System.out.println(Thread.currentThread().getName() + " 任务执行over ");
}
/**
* 线程池关闭后要执行的方法
*/
@Override
protected void terminated() {
super.terminated();
}
/**
* 暂停执行任务的方法
*/
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
/**
* 恢复执行任务的方法
*/
public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}
5 自定义Runnable
此Runnable可设置优先级
public abstract class CustomRunnable implements Runnable,Comparable<CustomRunnable> {
private int priority;
public CustomRunnable(int priority) {
if (priority<0)
throw new IllegalArgumentException();
this.priority = priority;
}
@Override
public int compareTo(CustomRunnable another) {
int my = this.getPriority();
int other = another.getPriority();
if (my>other){
return -1;
}else{
return 0;
}
}
@Override
public void run() {
doRun();
}
public abstract void doRun();
public int getPriority() {
return priority;
}
}
6 结合使用
private void customThreadFunction2() {
CustomExpanThreadPool threadPoolExecutor = CustomExpanThreadPool.getInstance();
/**
* 添加执行任务
*/
for (int i=1;i<=20;i++){
final int prites = i;
threadPoolExecutor.execute(new CustomRunnable(prites){
@Override
public void doRun() {
String name = Thread.currentThread().getName();
System.out.println("curentThread name is "+name +"and prites is "+prites);
SystemClock.sleep(1000);
}
});
}
}