1.java 默认提供的线程池类型
newCachedThreadPool:创立一个可缓存的线程池,线程池容量为无限大,当第二个工作开始时第一个工作曾经实现,则复用之前的线程,不会创立新线程,可灵便回收线程。
newFixedThreadPool:创立一个有固定代销的线程池,可管制最大并发数(线程数量),超出的线程会在期待队列中期待。
newScheduledThreadPool:创立一个定长线程池,反对定时及周期性工作执行。
newSingleThreadExecutor:创立一个单线程化的线程池,它只有惟一的一个工作线程来执行工作,所有工作都只能依照指定的程序执行。
2. 创立线程池的正确姿态
应用 java 默认提供的线程池的创立办法是能够抉择的计划,然而在有的时候会呈现内存溢出的谬误。
// 创立对应性能的线程池
ExecutorService executor1 = Executors.newCachedThreadPool();
ExecutorService executor2 = Executors.newFixedThreadPool(2);
ExecutorService executor3 = Executors.newScheduledThreadPool(4);
ExecutorService executor4 = Executors.newSingleThreadExecutor();
// 调用线程池执行相应工作
executor1.execute(new Runnable() {
@Override
public void run() {for (int i = 0; i < 100000; i++) {System.out.println(Thread.currentThread().getName() + "执行" + i);
}
}
});
举荐的创立线程池的形式:
ExecutorService executorService = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
即应用 new ThreadPoolExecutor()并本人初始化响应的参数。上面介绍一下各个参数的意义。
ThreadPoolExecutor 的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
corePoolSize:线程池外围线程数量,也就是即便闲暇也不会被销毁的线程。
maximumPoolSize:线程池最大线程数量。
keepAliveTime:闲暇线程存活工夫,如果以后线程处于闲暇状态且线程数量大于 corePoolSize,那么这个线程将会被销毁。
unit:keepAliveTime 的计量单位。
BlockingQueue:阻塞队列,即当一个工作进入到线程池后如果当初没有闲暇的外围线程,就会被增加到阻塞队列中期待直到有外围线程闲暇。而当阻塞队列也满了之后才会调用外围线程之外,最大线程之内的闲暇线程。
3. 线程池的回绝策略
当线程池中的期待队列和最大闲暇线程都满了的时候,就会执行当时设定好的回绝策略,java 提供了 4 种回绝策略。
1.CallerRunsPolicy:该策略下,在调用者线程中间接执行被回绝人物的 run()办法,除非线程池曾经 shutdown,则间接摈弃工作。
2.AbortPolicy:该策略下,间接抛弃工作,并抛出 RejectedExecutionException 异样。
3.DiscardPolicy:该策略下,间接抛弃工作,什么都不做。
4.DiscardOldestPolicy:该策略下,摈弃队列最早的那个工作,而后尝试把这次回绝的工作放入队列中。
4. 线程池的工作过程
- 一个线程工作达到线程池
- 查看以后的外围线程是否有闲暇线程,如有则间接应用闲暇的外围线程执行工作
- 如果以后外围线程全为应用状态,则将当前任务增加到期待队列中
- 如果以后外围线程与期待队列均为满状态,则调用非核心线程执行工作
- 如果以后外围线程,期待队列与非核心线程均为满状态,则执行线程池的回绝策略。
5. 间接应用 Executors 创立线程池会有什么问题?
如果咱们应用 java 默认提供的 Executors 创立线程池。
当咱们创立 FixedThreadPool 和 SingleThreadExecutor 的时候,因为默认的创立办法的参数中阻塞队列的长度为 Integer.MAX_VALUE,这就会导致当工作数量很多的时候队列沉积大量的工作申请造成内存溢出 (OOM)。
当咱们创立 CachedThreadPool 和 ScheduledThreadPool 的时候,因为默认的创立办法的参数中外围线程的大小为 Integer.MAX_VALUE,这就会导致当工作数量很多的时候创立大量的线程,造成内存溢出 (OOM)。
下面两个问题的外围就是在于默认提供的参数大小往往不是适合的,因而才倡议咱们应用 new ThreadPoolExecutor 的办法创立线程池,并手动初始化各参数。