为什么使用线程池:
降低资源消耗,通过重复利用已创建的线程,减少了线程的创建和销毁,从而达到了减少不必要的资源消耗。当任务进入到线程池中不必要再重新创建线程,提高了运行效率。对线程进行可控的管理,因为线程是稀缺资源,要适当的进行分配和调优和监控。
线程池的七个入参:
线程池中有七个构造函数,下面会对着七个函数进行解析:
1. corePoolSize:
核心线程数大小,这些线程不会被销毁。
2. maximumPoolSize:
最大线程数,指定了该线程中最大的线程数量。
3. keepAliveTime
非核心线程的存活时间,大于核心线程数的线程都为非核心线程数。
4. unit:
非核心线程存活的时间单位
5. workQueue:
任务队列,提交的任务会被放进这个队列里,有五种队列:
- ArrayBlockingQueue :数组阻塞队列,数组结构,初始化传入大小,默认非公平锁。
- LinkedBlockingQueue :链表阻塞队列,链表结构,默认大小(2的31次方减1,超级大)
- SynchronousQueue :同步队列,容量为0,类似于通道。
- PriorityBlockingQueue :顺序阻塞队列,无界,默认元素排序。
- DelayQueue :延时队列,元素有过期时间,过期了才能被取出来。
6. threadFactory:
创建新线程时候使用的工厂,一般是默认的。
7. handler
拒绝策略,当线程使用到最大的时候,再来的新任务就会触发拒绝策略:
- AbortPolicy:丢弃任务并抛出异常。
- DiscardPolicy:丢弃任务不抛出异常。
- DiscardOldestPolicy:丢弃队列里最老的任务。
- CallerRunsPolicy:谁提交的任务谁来执行,减缓了提交任务的速率。
创建线程的四种方式:
- newCachedThreadPool :
创建一个非核心线程的线程池,如果线程60秒未使用,那么将被移除。
public class KobeCachedTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "鸡你太美" + i);
}
}
});
}
executorService.shutdown();
}
}
- newFixedThreadPool:
创建一个固定的核心线程池,线程将会一直存在线程池当中。
public class KobeFixedTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int i = 0; i < 5; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "鸡你太美" + i);
}
}
});
}
executorService.shutdown();
}
}
- newScheduledThreadPool :
创建一个线程池,它可以安排在固定时间后运行命令。
public class KobeScheduledTest {
public static void main(String[] args) {
//创建个间隔时间为8秒的 定时执行线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
System.out.println("任务开始时间:"+new Date());
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("任务执行时间:"+new Date());
}
},8, TimeUnit.SECONDS);
scheduledExecutorService.shutdown();
}
}
- newSingleThreadExecutor :
这个线程池中只能一个线程,可以保证先进先出的顺序:
public class KobeSingleTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "鸡你太美" + i);
}
}
});
}
executorService.shutdown();
}
}
线程池的五种状态
- Running:运行状态,正常执行任务。
- Shutdown:关闭状态,该线程池不接受新的任务,等待现有任务执行结束。
- Stop:停止状态,不接受任务,不处理线程池中还未执行的任务,停止当前正在执行的任务。
- Tidying:整理状态,任务数为0的时候,线程池即将进入下一个状态。
- Terminated:结束状态,线程池完全结束。
知识扩展:
阿里开发手册并不推荐使用Java内置Excutors创建线程池,为了规避资源消耗,推荐开发人员根据服务器环境自行配置线程池参数。
newFixedThreadPool和newSingleThreadExecutor使用的都是LinkedBlockingQueue队列,默认大小为2的31次方减一(类似于无界),当大量请求过来时会容易产生OOM。
newScheduledThreadPool和newCachedThreadPool,一个是周期定时执行一个创建非核心线程数为2的31次方减一(类似于无界),容易导致cpu突然暴增。