面试题:一个线程池,core 7;max 20;queue:50;100 个并发进来如何分配:
# 7个会立即执行,50个会进入队列,再开13个进行执行,剩余30个使用拒绝策略
线程池:3 大方法,7 大参数,4 种拒绝策略
池化技术
程序的运行,本质:占用系统的资源!优化资源的使用!
线程池、连接池、内存池、对象池。。。创建、销毁 => 十分浪费资源
池化技术:事先准备好一些资源,有人要用,就来拿,用完之后归还
线程池的好处
1、降低资源的损耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
2、提高响应的速度
当线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
3、方便管理
线程池会根据当前系统特点,对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池可以统一分配
线程复用,可以控制最大并发数,管理线程
线程池:3 大方法
package com.xoste.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author 小斯特
* @date 2021/11/23 16:27
* Executors 工具类、3大方法
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 单个线程
ExecutorService threadPool = Executors.newSingleThreadExecutor();
// 创建一个固定的线程池大小
ExecutorService threadPool2 = Executors.newFixedThreadPool(5);
// 可伸缩的,遇强则强,遇弱则弱
ExecutorService threadPool3 = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 100; i++) {
threadPool3.execute(() -> {
System.out.println(Thread.currentThread().getName() + " ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool3.shutdown();
}
}
}
线程池:7大参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeaP33zo-1646724702419)(JUC.assets\image-20211123162036611-1637673805309-1637673810285.png)]
// 单线程的线程池,后台从队列里面获取任务,挨个执行
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// 固定大小,core=max,都不可回收
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
// core=0,所有都可回收
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// 定时任务的线程池
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
// 本质: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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}`
4 种拒绝策略
默认拒绝策略
手动创建一个线程池
package com.xoste.pool;
import java.util.concurrent.*;
/**
* @author 小斯特
* @date 2021/11/23 16:27
* Executors 工具类、3大方法
*
* // 银行满人了,还有人进来,不处理这个人,抛异常
* new ThreadPoolExecutor.AbortPolicy()
* //既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它(哪来的,去哪里)
* new ThreadPoolExecutor.CallerRunsPolicy()
* // 队列满了,不会抛出异常!
* new ThreadPoolExecutor.DiscardPolicy()
* // 队列满了,直接丢弃最老的任务,重新尝试执行当前任务
* new ThreadPoolExecutor.DiscardOldestPolicy()
*
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 自定义线程池!工作 ThreadPoolExecutor
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2,// 核心线程池大小
5,// 最大核心线程池大小
3,// 超时了没有人就会释放(存活时间)
TimeUnit.SECONDS,// 超时单位
new LinkedBlockingQueue<>(3),// 阻塞队列容器
Executors.defaultThreadFactory(),// 线程工厂,创建线程,一般不用动
// 队列满了,直接丢弃最老的任务,重新尝试执行当前任务
new ThreadPoolExecutor.DiscardOldestPolicy() // 拒绝策略);
try {
for (int i = 0; i < 9; i++) {
threadPool.execute(() -> {
// 使用了线程池之后,使用线程池来创建线程
System.out.println(Thread.currentThread().getName() + " ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
}
小结–拓展
池的最大的大小如何去设置!
了解:CPU密集型,IO密集型(调优)
// 最大线程到底该如何定义
// 1.CPU 密集型,几核,就是几,可以保持 CPU 的效率最高!
// 2.IO 密集型 > 判断程序中,十分耗 IO 的线程,
// 程序 15个大型任务 IO十分占用资源
// 获取 CPU 的核数
System.out.println(Runtime.getRuntime().availableProcessors());