「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」
三、Android 中常用的几种线程池
1.FixedThreadPool (可重用固定线程数)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
特点:参数为核心线程数,只有核心线程,无非核心线程,并且阻塞队列无界
创建
//创建fixed线程池
final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
使用
/**
* fixed线程池
*/
mFixedPoolThread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i<30;i++){
final int finali = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
Log.d("Thread", "run: "+finali);
Log.d("当前线程:",Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
fixedThreadPool.execute(runnable);
}
}
});
结果为每2s打印5次任务,跟上面的基础线程池类似
2.CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
CachedThreadPool中是没有核心线程的,但是它的最大线程数却为Integer.MAX_VALUE,另外,CachedThreadPool是有线程超时机制的,它的超时时间为60秒。
由于最大线程数为无限大,所以每当添加一个新任务进来的时候,如果线程池中有空闲的线程,则由该空闲的线程执行新任务;如果没有空闲线程,则创建新线程来执行任务。
根据CachedThreadPool的特点,在有大量耗时短的任务请求时,可使用CachedThreadPool,因为当CachedThreadPool中没有新任务的时候,它里边所有的线程都会因为60秒超时而被终止
创建
//创建Cached线程池
final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
使用
/**
* cached线程池
*/
mCachedPoolThread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i<30;i++){
final int finali = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
Log.d("Thread", "run: "+finali);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
cachedThreadPool.execute(runnable);
}
}
});
结果:过2s后直接打印30个任务
3.SingleThreadPool(单个核线的fixed)
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
它的核心线程数量是固定的,但是非核心线程无穷大。当非核心线程闲置时,则会被立即回收。
ScheduledThreadPool也是四个当中唯一一个具有定时定期执行任务功能的线程池。它适合执行一些周期性任务或者延时任务。
创建
//创建Single线程池
final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
使用
/**
* single线程池
*/
mSinglePoolExecute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i<30;i++){
final int finali = i;x
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
Log.d("Thread", "run: "+finali);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
singleThreadExecutor.execute(runnable);
}
}
});
结果:每2s打印一个任务,由于只有一个核心线程,当被占用时,其他的任务需要进入队列等待。
四、终止线程池中的某个线程
一般线程执行完run方法之后,线程就正常结束了,因此有如下几种方式来实现:
1.利用 Future 和 Callable
步骤:
实现 Callable 接口
调用 pool.submit() 方法,返回 Future 对象
用 Future 对象来获取线程的状态。
private void cancelAThread() {
ExecutorService pool = Executors.newFixedThreadPool(2);
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("test");
return "true";
}
};
Future<String> f = pool.submit(callable);
System.out.println(f.isCancelled());
System.out.println(f.isDone());
f.cancel(true);
}
2.利用 volatile 关键字,设置退出flag, 用于终止线程
public class ThreadSafe extends Thread {
public volatile boolean isCancel = false;
public void run() {
while (!isCancel){
//TODO method();
}
}
}
3.interrupt()方法终止线程,并捕获异常
public class ThreadSafe extends Thread {
@Override
public void run() {
while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
try{
//TODO method();
//阻塞过程捕获中断异常来退出
}catch(InterruptedException e){
e.printStackTrace();
break;//捕获到异常之后,执行break跳出循环。
}
}
}
}