一、为什么要使用线程池?
java支持多线程开发,也就是支持多个任务并行运行,我们也知道线程的生命周期中包括创建、就绪、运行、阻塞、销毁等阶段,所以如果要执行的任务很多,每个任务都需要一个线程的话,那么频繁的创建、销毁线程会比较耗性能。
有了线程池就不要创建更多的线程来完成任务,因为线程可以重用,另外,如果无限制的创建大量的线程,大量的线程会占用内存资源并且可能会导致Out of Memory。
二、使用线程池的好处?
1.我们可以把创建和销毁的线程的过程去掉
2.提高效率 创建好一定数量的线程放在池中,等需要使用的时候就从池中拿一个,这要比需要的时候创建一个线程对象要快的多。
三、线程池的种类
1.FixedThreadPool
特点:
- 核心线程数 == 最大线程数(没有救急线程),自然也无需超时时间
- 阻塞队列是无界的,可以放任意数量的任务
- 适用于任务量已知,相对耗时的任务
public static ExecutorService newFixedThreadPool(int threads) {
return new ThreadPoolExecutor(threads,threads,
0L, TimeUnit.MICROSECONDS,
new LinkedBlockingDeque<Runnable>());
}
2.CachedThreadPool
特点:
- 全部都是救急线程(60s后回收)
- 救急线程可以无限创建
- 队列采用了SynchronousQueue实现特点是,它没有容量,没有线程来取是放不进去的(一手交钱,一手交货)
- 整个线程线程数会根据任务量不断增长,没有上限,任务执行完毕,60s后释放线程
- 合任务数比较密集,但每个任务执行时间较短的情况
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0,
Integer.MAX_VALUE,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<>());
}
3.ScheduledThreadPool()
定长线程池:
- 支持定时及周期性任务执行
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor():
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
4.SingleThreadExecutor
特点:
- 线程数始终为1,不能修改。希望多个任务排队执行。任务数多于 1 时,会放入无界队列排队。 任务执行完毕,这唯一的线程也不会被释放
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
四、 线程池的使用
public class TestThreadPool {
public static void main(String[] args) {
//1.1创建固定线程个数的线程池
//ExecutorService es=Executors.newFixedThreadPool(4);
//1.2创建缓存线程池,线程个数由任务个数决定
ExecutorService es=Executors.newCachedThreadPool();
//1.3创建单线程线程池
//Executors.newSingleThreadExecutor();
//1.4创建调度线程池 调度:周期、定时执行
//Executors.newScheduledThreadPool(corePoolSize)
Executors.newScheduledThreadPool(3);
//2创建任务
Runnable runnable=new Runnable() {
private int ticket=100;
@Override
public void run() {
while(true) {
if(ticket<=0) {
break;
}
System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
ticket--;
}
}
};
//3提交任务
for(int i=0;i<5;i++) {
es.submit(runnable);
}
//4关闭线程池
es.shutdown();//等待所有任务执行完毕 然后关闭线程池,不接受新任务。
}
}