1.为什么要使用线程池?
(1)在android中,使用线程池可以更加高效地管理线程
(2):如果使用多线程异步来处理相关任务的时,依旧使用new thread方法,根据java的GC机制,会造成线程频繁地创建和销毁
(3):不合理地调用销毁线程,会造成程序卡顿,用户的体验感极差
(4):为了较好地管理线程,于是使用线程池同一管理线程的资源,线程在使用后不会立马被GC销毁,而是存在于队列中等待下一次的使用,这样很好地解决了线程不停创建销毁带来的卡顿和资源分配问题
2.几种基本的线程池
2-1:CacheThreadPool
说明:创建一个可缓存的线程池,如果线程池的长度超过了处理的需要 可以灵活的回收空闲线程 如无可回收
//缓存线程池
public void testCache() {
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();//创建一个线程池对象
//实现10个并发的任务
for (int i = 0; i < 10; i++) {
final int temp = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cacheThreadPool.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG", Thread.currentThread().getName() + " " + temp);
}
});
}
}
//按钮的onClick属性
public void usePool(View view) {
testCache();
//testFixed();
//testSingle();
//testSchedule();
}
测试结果:
2-2:FixThreadPool
说明:创建一个定长的线程池,可以控制线程池的最大并发数,超过的线程会在队列中进行等待
public void testFixed() {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//代表着有多少个并发
for (int i = 0; i < 10; i++) {
final int temp = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG", Thread.currentThread().getName() + " " + temp);
}
});
}
}
//onClick属性
public void usePool(View view) {
//testCache();
testFixed();
//testSingle();
//testSchedule();
}
测试结果:
2-3:singleThreadPool
说明:
创建一个单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有的任务都按照指定的顺序去执行(FIFO,LIFO,优先级)
public void testCache() {
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();//创建一个线程池对象
//实现10个并发的任务
for (int i = 0; i < 10; i++) {
final int temp = i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
cacheThreadPool.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG", Thread.currentThread().getName() + " " + temp);
}
});
}
}
//按钮的onClick属性
public void usePool(View view) {
//testCache();
//testFixed();
testSingle();
//testSchedule();
}
测试结果:
2-4:SchedueldThreadPool
创建一个单例定长的线程池,支持定时或者定周期执行任务
这是一种比较特殊的线程池,首先定义为单例线程池,然后,在单例线程池的基础上进行拓展功能
//定长定时线程池
//先说明单例 然后再调整时间
public void testSchedule() {
//和上述的创建方法有所不同
Log.d("TAG", "testSchedule");
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
// //定时3s以后执行
// scheduledExecutorService.schedule(
// new Runnable() {
// @Override
// public void run() {
// Log.d("TAG", "delay 3 seconds");
// }
// }
// , 3, TimeUnit.SECONDS);
//定时定周期操作
//定时2s之后执行,每隔3s执行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("TAG","Let us go");
}
}, 2, 3, TimeUnit.SECONDS);//两个数字参数 前一个参数是delay的时间 后一个是设置周期时间
}
}
//按钮的onClick属性
public void usePool(View view) {
//testCache();
//testFixed();
//testSingle();
testSchedule();
}
tips:通过使用此种方法可以实现定时,定周期的效果
测试结果:
此外,线程池还有以下几种方法:
1.shutDown() 关闭线程池,不影响已经提交的任务
2.shutDownNow() 关闭线程池,并尝试去终止正在执行的线程
3.allowCoreThreadTimeOut(boolean value) 允许核心线程闲置超时时被回收
4.submit 进行线程池的提交。
5.beforeExecute() - 任务执行前执行的方法
6.afterExecute() -任务执行结束后执行的方法
7.terminated() -线程池关闭后执行的方法