说起线程池,我们先来简单说一下线程池的好处:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。
Java通过Executors提供四种线程池,分别为:
(1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
(3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
(4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
关于这四种线程池吧,说真的,平时没怎么用,忘得也快,今天就特意写了例子来增加自己的印象,上代码:
private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINA);
private static void testExecutorService(ExecutorService executorService){
for(int i=0;i<10;i++){
final int finalI = i;
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("当前线程"+ finalI+",名字为:"+Thread.currentThread().getName()+",时间:"+df.format(new Date()));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
executorService.shutdown();
}
我们先定义了公共的测试方法,然后我们将创建四种不同的线程池进行测试
(1)newCachedThreadPool
public static void main(String[] args) {
ExecutorService cachedThreadPool= Executors.newCachedThreadPool();
testExecutorService(cachedThreadPool);
}
打印结果:
当前线程3,名字为:pool-1-thread-4,时间:2019-03-14 16:57:52
当前线程4,名字为:pool-1-thread-5,时间:2019-03-14 16:57:52
当前线程1,名字为:pool-1-thread-2,时间:2019-03-14 16:57:52
当前线程6,名字为:pool-1-thread-7,时间:2019-03-14 16:57:52
当前线程2,名字为:pool-1-thread-3,时间:2019-03-14 16:57:52
当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:57:52
当前线程7,名字为:pool-1-thread-8,时间:2019-03-14 16:57:52
当前线程5,名字为:pool-1-thread-6,时间:2019-03-14 16:57:52
当前线程9,名字为:pool-1-thread-10,时间:2019-03-14 16:57:52
当前线程8,名字为:pool-1-thread-9,时间:2019-03-14 16:57:52
从这结果可以看出,newCachedThreadPool就是壕,线程池为无限大,如果第二个任务来了,而第一个还未完成,它会创建出新的线程来执行新的任务,就比如上面例子中,循环了10个,相当于来了十个任务,很豪气地创建了10个线程,所以几乎是同时执行完毕的。
而如果当第二个任务来了,而第一个任务已经执行完,则会复用第一个任务的线程,不会再新建线程。
(2)newFixedThreadPool
public static void main(String[] args) {
ExecutorService fixedThreadPool= Executors.newFixedThreadPool(5);
testExecutorService(fixedThreadPool);
}
打印结果:
当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:55:59
当前线程3,名字为:pool-1-thread-4,时间:2019-03-14 16:55:59
当前线程1,名字为:pool-1-thread-2,时间:2019-03-14 16:55:59
当前线程2,名字为:pool-1-thread-3,时间:2019-03-14 16:55:59
当前线程4,名字为:pool-1-thread-5,时间:2019-03-14 16:55:59
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 16:56:01
当前线程5,名字为:pool-1-thread-4,时间:2019-03-14 16:56:01
当前线程7,名字为:pool-1-thread-2,时间:2019-03-14 16:56:01
当前线程8,名字为:pool-1-thread-3,时间:2019-03-14 16:56:01
当前线程9,名字为:pool-1-thread-5,时间:2019-03-14 16:56:01
这是一个定长的线程池,如上面例子,共创建了5个线程,而总共有10个任务,所以第一次执行后,会休眠2秒再次执行,结果已经很好的说明这一点。
(3) newScheduledThreadPool
public static void main(String[] args) {
ExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(5);
testExecutorService(scheduledThreadPool);
}
这个也是一个定长的线程池,如果执行上面代码的话,其结果与newFixedThreadPool 是一样的,这里就不列出打印结果了,但不同的是它支持定时及周期性任务的执行,我们也简单写一下例子:
private static int count=0;
public static void main(String[] args) {
final ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(1);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
count++;
System.out.println("当前线程"+ count+",名字为:"+Thread.currentThread().getName()+",时间:"+df.format(new Date()));
if(count==10){
scheduledThreadPool.shutdown();
}
}
},0,1,TimeUnit.SECONDS);
}
打印结果:
当前线程1,名字为:pool-1-thread-1,时间:2019-03-14 20:59:03
当前线程2,名字为:pool-1-thread-1,时间:2019-03-14 20:59:04
当前线程3,名字为:pool-1-thread-1,时间:2019-03-14 20:59:05
当前线程4,名字为:pool-1-thread-1,时间:2019-03-14 20:59:06
当前线程5,名字为:pool-1-thread-1,时间:2019-03-14 20:59:07
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 20:59:08
当前线程7,名字为:pool-1-thread-1,时间:2019-03-14 20:59:09
当前线程8,名字为:pool-1-thread-1,时间:2019-03-14 20:59:10
当前线程9,名字为:pool-1-thread-1,时间:2019-03-14 20:59:11
当前线程10,名字为:pool-1-thread-1,时间:2019-03-14 20:59:12
(4)newSingleThreadExecutor
public static void main(String[] args) {
ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();
testExecutorService(singleThreadExecutor);
}
打印结果:
当前线程0,名字为:pool-1-thread-1,时间:2019-03-14 16:56:57
当前线程1,名字为:pool-1-thread-1,时间:2019-03-14 16:56:59
当前线程2,名字为:pool-1-thread-1,时间:2019-03-14 16:57:01
当前线程3,名字为:pool-1-thread-1,时间:2019-03-14 16:57:03
当前线程4,名字为:pool-1-thread-1,时间:2019-03-14 16:57:05
当前线程5,名字为:pool-1-thread-1,时间:2019-03-14 16:57:07
当前线程6,名字为:pool-1-thread-1,时间:2019-03-14 16:57:09
当前线程7,名字为:pool-1-thread-1,时间:2019-03-14 16:57:11
当前线程8,名字为:pool-1-thread-1,时间:2019-03-14 16:57:13
当前线程9,名字为:pool-1-thread-1,时间:2019-03-14 16:57:15
从名字就知道,这个只有唯一一个工作线程,所以一个任务一个任务的依次执行,正如结果那样。
事实证明,动手才是王道,通过例子,我们可以更好的了解四种不同线程池之区别,也有利于我们更好的记忆及使用。










网友评论