每天一篇系列:
强化知识体系,查漏补缺。
欢迎指正,共同学习!
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
线程池可以复用线程避免频繁创建和销毁。
public class MyThread extends Thread {
public String name;
public MyThread(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "正在执行...." + name);
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorTest {
public static final int NUM_THREADS = 10;
public static List<Thread> threads = Collections
.synchronizedList(new ArrayList<Thread>());
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
// 创建一个可重用固定线程数的线程池
// ExecutorService pool = Executors.newFixedThreadPool(4);
// 创建一个可重用固定线程数的线程池
// ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < NUM_THREADS; i++) {
Thread t = new MyThread(" i am " + i);
threads.add(t);
}
for (int i = 0; i < NUM_THREADS; i++) {
pool.execute(threads.get(i));
}
// 关闭线程池
pool.shutdown();
}
}
java提供了四种线程池的实现:
-
newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
输出结果:
pool-1-thread-1正在执行.... i am 0
pool-1-thread-1正在执行.... i am 1
pool-1-thread-1正在执行.... i am 2
pool-1-thread-1正在执行.... i am 3
pool-1-thread-1正在执行.... i am 4
pool-1-thread-1正在执行.... i am 5
pool-1-thread-1正在执行.... i am 6
pool-1-thread-1正在执行.... i am 7
pool-1-thread-1正在执行.... i am 8
pool-1-thread-1正在执行.... i am 9
可以看到线程池里面只有线程1,并且excute()执行复用线程1线程来执行新的任务。
只有一个核心线程,确保所有任务都在同一线程中按顺序完成。因此不需要处理线程同步的问题。
2.newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
输出结果:
pool-1-thread-1正在执行.... i am 0
pool-1-thread-1正在执行.... i am 4
pool-1-thread-1正在执行.... i am 5
pool-1-thread-1正在执行.... i am 6
pool-1-thread-1正在执行.... i am 7
pool-1-thread-1正在执行.... i am 8
pool-1-thread-1正在执行.... i am 9
pool-1-thread-2正在执行.... i am 1
pool-1-thread-3正在执行.... i am 2
pool-1-thread-4正在执行.... i am 3
可以看到,最终线程池里面只有四条线程,执行是无序的,但是线程还是被复用了。
FixThreadPool只有核心线程,并且数量固定的,也不会被回收,所有线程都活动时,因为队列没有限制大小,新任务会等待执行。由于线程不会回收,FixThreadPool会更快地响应外界请求,这也很容易理解。
3. newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。CachedThreadPool是有线程超时机制的,它的超时时间为60秒
输出结果:
pool-1-thread-1正在执行.... i am 0
pool-1-thread-2正在执行.... i am 1
pool-1-thread-3正在执行.... i am 2
pool-1-thread-5正在执行.... i am 4
pool-1-thread-6正在执行.... i am 5
pool-1-thread-7正在执行.... i am 6
pool-1-thread-9正在执行.... i am 8
pool-1-thread-8正在执行.... i am 7
pool-1-thread-10正在执行.... i am 9
pool-1-thread-4正在执行.... i am 3
可以看到线程池里面一共有10条线程,执行是无序的。
CachedThreadPool只有非核心线程,最大线程数非常大,所有线程都活动时,会为新任务创建新线程,否则利用空闲线程(60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能)处理任务。比较适合执行大量的耗时较少的任务,这样才能达到线程被复用的效果,最大程度上减少创建和销毁线程的情况。
4.newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。可以理解为能够定时的newCachedThreadPool。