池化技术
程序运行的本质:占用系统资源
所以我们要优化资源的使用,就要用到池化技术(线程池,连接池,内存池,对象池…..)
事先准备好一些资源,有人呢要用 ,就来拿 ,用完还回来
好处:降低资源消耗,提高响应的速度,方便管理,线程复用,控制对大并发数,管理线程
Executors创建线程池的三个方法
// Executors 工具类 3大方法
public class Demo
{
public static void main(String[] args)
{
// ExecutorService executorService = Executors.newSingleThreadExecutor();//单个
// ExecutorService executorService = Executors.newFixedThreadPool(5);//固定的 线程 池
ExecutorService executorService = Executors.newCachedThreadPool();//可以伸缩的,遇强则强,遇弱则弱
try
{
for (int i = 0; i < 10; i++)
{
//使用线程池创建线程
executorService.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
}
finally
{
//线程池必须要关闭
executorService.shutdown();
}
}
}
线程池的七个参数
看一下 newSingleThreadExecutor() 的源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
看一下 newFixedThreadPool(int nThreads) 的源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
看一下 newCachedThreadPool() 的源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看到底层都是在 new ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
看到了七个参数:
int corePoolSize: 核心线程池大小
int maximumPoolSize: 最大核心线程池大小
Long keepAliveTime: 超时了没有人调用就会释放
TimeUnit unit: 超时单位
BlockingQueue<Runnable> workQueue: 阻塞队列
ThreadFactory threadFactory: 线程工厂,创建线程,一般不用修改
RejectedExecutionHandler handler 拒绝策略
四种拒绝策略:
Executors创建线程池拒绝策略默认是 AbortPolicy
AbortPolicy :超出了最大承载数量(队列满了)抛出异常
RejectedExecutionException :被拒绝执行异常
CallerRunsPolicy :超出了最大承载数量(队列满了)不抛出异常 哪来的回哪哪里去 也就是说线程池处理不了,返回给main执行
DiscardOldestPolicy : 超出了最大承载数量(队列满了)不抛出异常,尝试和最早的线程竞争,竞争失败了就放弃
DiscardPolicy : 超出了最大承载数量(队列满了)不抛出异常,放弃任务
再来看看三个方法的里面的int corePoolSize 和int maximumPoolSize 参数
newSingleThreadExecutor()
核心线程数:1
最大线程数:1
newFixedThreadPool(int nThreads)
核心线程数:nThreads
最大线程数:nThreads
newCachedThreadPool()
核心线程数:0
最大线程数:Integer.MAX_VALUE 也就是2147483647
[强制]线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
- FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer .MAX_ _VALUE,可能会堆积大量的请求,从而导致00M。
- CachedThreadPool和ScheduledThreadPool: 允许的创建线程数量为Integer.MAX__VALUE,可能会创建大量的线程,从而导致00M。
———阿里巴巴开发手册
我们要用 ThreadPoolExecutor 来创建线程池
看看这个图会更好理解线程池
用代码实现一下
public class Bank
{
public static void main(String[] args)
{
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
2, //默认两个柜台
5, //最多五个柜台
3, //柜台等待 3秒
TimeUnit.SECONDS, //等待单位
new LinkedBlockingQueue<>(5), // 侯客区位置5
Executors.defaultThreadFactory(), //线程工厂
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人来,不予理睬,抛出异常
);
try
{
for (int i = 0; i <11 ; i++)
{
poolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
}
finally
{
poolExecutor.shutdown();
}
}
}
运行结果
pool-1-thread-1办理业务
pool-1-thread-4办理业务
pool-1-thread-3办理业务
pool-1-thread-2办理业务
pool-1-thread-4办理业务
pool-1-thread-3办理业务
pool-1-thread-5办理业务
pool-1-thread-1办理业务
pool-1-thread-4办理业务
pool-1-thread-2办理业务
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.y1.pool.Bank$$Lambda$1/363771819@10f87f48 rejected from java.util.concurrent.ThreadPoolExecutor@b4c966a[Running, pool size = 5, active threads = 0, queued tasks = 0, completed tasks = 10]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.y1.pool.Bank.main(Bank.java:30)
可以看出来了11个“客户”,1 2 3 4 5 个柜台全部开始运行,但是超出了最大承载数量 (阻塞队列+最大核心线程池),因为拒绝策略设置了AbortPolicy,抛出错误RejectedExecutionException :被拒绝执行异常
最大线程该数设定的两种方式:
CPU密集型:几核CPU就可以设置线程数为几,效率最高,但是呢你不写死对吧…
所以呢要获取一下你的CPU核数:
Runtime.getRuntime().availableProcessors(); //获取CPU核数
IO密集型:判断程序中有多少个特别消耗IO的线程,设置最大线程大于这个数量