背景:每出现一个耗时操作都去创建一个新的线程必然不优美,既没有高并发,对资源的共享和竞争也是比较混乱。总之:
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。
一、newCacheThreadPool一个无限大并可以缓存的线程池。在之前创建新线程的时刻首先复用已经创建过的空闲线程。
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
for ( int i = 0 ; i<10 ; i++ ){
final int index = i;
try {
Thread.sleep(index*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//拿到线程的对象的时候将线程扔到线程池中
cacheThreadPool.execute(new Runnable() {
@Override
public void run() {
Log.d( "newCachedThreadPool" , "" + index );
}
});
}
二、newFixedThreadPool 可以控制最大并发数的线程池。超过最大并发数的线程进入等待队列。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i= 0;i<10;i++){
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
Log.d("newFixedThreadPool",index+"");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
三、newScheduledThreadPool 一个可以定时执行的线程池。
延时1s执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
Log.d("newScheduledThreadPool","延期3秒执行");
}
},3, TimeUnit.SECONDS);
延时1s后每隔3s执行一次
public void initImTimeThreadPool(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("newScheduledThreadPool","延时1s后每3s执行一次");
}
},1,3,TimeUnit.SECONDS);
}
四、newSingleThreadExecutor 单线程化线程池。支持FIFO、LIFO的优先级执行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i<10 ;i++){
final int index = i ;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
Log.d("newSingleThreadExecutor",""+index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
那么问题来了,以上都是讲创建线程池并且将线程扔到线程池里面,那么,对于在线程池中的线程,我们该如何进行管理呢?
execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,
通过这个方法可以向线程池提交一个任务,交由线程池去执行。
submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,
在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,
它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,
只不过它利用了Future来获取任务执行结果(Future相关内容将在下一篇讲述)。
shutdown()和shutdownNow()是用来关闭线程池的。