一、线程池简介
其实所有池化技术,初衷都是节约资源,提升性能,线程池也不例外,线程的创建和销毁非常耗资源,不适合在实际的工作中使用。
线程池可以对线程进行重复利用,很好的节约了资源。
二、线程池参数介绍
int corePoolSize 核心线程数;线程池常驻线程数量
int maximumPoolSize 最大线程数;当阻塞队列已满,线程池所能扩容的最大数量
long keepAliveTime 空闲时间;扩容的线程所能存活的时间。
TimeUnit unit 空闲时间单位
BlockingQueue<Runnable> workQueue 阻塞队列;当核心线程都在工作,再有请求,就会入队列进行等待。
ThreadFactory threadFactory 线程创建工厂,一般使用默认线程创建工程即可
RejectedExecutionHandler handler 拒绝策略;当线程池中线程数量已达到最大线程数,队列也已满,再有请
拒绝策略类型
AbortPolicy (默认):直接抛出 RejectedExecutionException异常阻止系统正常运知。
CallerRunsPolicy:"调用者运行"一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务。
DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。
三、jdk所提供的线程池
1 newSingleThreadExecutor
> 创建方式 Executors.newSingleThreadExecutor()
> 源码 public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
> 特点:线程池中只有一个工作线程,核心线程数与最大线程数一样。
2 newFixedThreadPool
> 创建方式 Executors.newFixedThreadPool(int)
> 源码 public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
> 特点:自定义核心线程数与最大线程数
3 newCachedThreadPool()
> 创建方式:Executors.newCachedThreadPool()
> 源码 public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
> 特点:不指定核心线程数与最大线程数,动态扩容。如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
四、不推荐Executors创建线程池
1、newSingleThreadExecutor与newFixedThreadPool未给任务队列LinkedBlockingQueue指定队列大小,而默认的队列容量极易导致内存溢出。
2、jdk自带的线程池拒绝策略默认都是AbortPolicy,直接抛异常无论是什么项目都无法接受
五、核心线程数配置说明
1、CPU密集型
- CPU密集的意思是该任务需要大量的运算,而没有阻塞,CPU一直全速运行。
- CPU密集任务只有在真正的多核CPU上才可能得到加速(通过多线程)
- CPU密集型任务配置尽可能少的线程数量
- 公式:(CPU核数+1)个线程的线程池
2、lO密集型
- 由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如CPU核数 * 2
- 在单线程上运行IO密集型的任务会导致浪费大量的CPU运算能力浪费在等待,
所以在IO密集型任务中使用多线程可以大大的加速程序运行,即使在单核CPU上,这种加速主要就
是利用了被浪费掉的阻塞时间。
- IO密集型时,大部分线程都阻塞,故需要多配置线程数:
参考公式:CPU核数/ (1-阻塞系数)
阻塞系数在0.8~0.9之间
比如8核CPU:8/(1-0.9)=80个线程数
3、动态获取当前机器cpu核数
Runtime.getRuntime().availableProcessors();
六、自定义线程池
package cn.hh.huhy;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author huhy
*/
public class ThreadPollDemo {
private static ThreadPollDemo threadPollDemo;
private static Lock lock = new ReentrantLock();
private ThreadPollDemo() {
}
public static final ThreadPollDemo createThreadPollDemo() {
if (Objects.isNull(threadPollDemo)) {
lock.lock();
if (Objects.isNull(threadPollDemo)) {
threadPollDemo = new ThreadPollDemo();
}
lock.unlock();
}
return threadPollDemo;
}
public void doSomething(ExecutorService threadPoll, int numOfRequest) {
System.out.println(((ThreadPoolExecutor) threadPoll).getRejectedExecutionHandler().getClass().getName() + "\n");
try {
for (int i = 0; i < numOfRequest; i++) {
final int tempInt = i;
threadPoll.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t 给用户:" + tempInt + " 办理业务");
});
}
TimeUnit.SECONDS.sleep(1L);
System.out.println("\n\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPoll.shutdown();
}
}
public ExecutorService newHhyThreadPollExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, int queueSize, RejectedExecutionHandler handler) {
return new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
new LinkedBlockingQueue<>(queueSize),
Executors.defaultThreadFactory(),
handler
);
}
public static void main(String[] args) {
// ThreadPollDemo threadPollDemo = ThreadPollDemo.createThreadPollDemo();
// threadPollDemo.doSomething(threadPollDemo.newHhyThreadPollExecutor(2, 5, 3, TimeUnit.SECONDS, 3, new ThreadPoolExecutor.AbortPolicy()), 10);
// threadPollDemo.doSomething(threadPollDemo.newHhyThreadPollExecutor(2, 5, 3, TimeUnit.SECONDS, 3, new ThreadPoolExecutor.CallerRunsPolicy()), 20);
// threadPollDemo.doSomething(threadPollDemo.newHhyThreadPollExecutor(2, 5, 3, TimeUnit.SECONDS, 3, new ThreadPoolExecutor.DiscardOldestPolicy()), 10);
// threadPollDemo.doSomething(threadPollDemo.newHhyThreadPollExecutor(2, 5, 3, TimeUnit.SECONDS, 3, new ThreadPoolExecutor.DiscardPolicy()), 10);
// int i = Runtime.getRuntime().availableProcessors();
// System.out.println("当前电脑的cpu核数为:"+i+"核");
}
}