admin管理员组文章数量:1794759
线程池(I)
现网故事
背景介绍
现象:内存不断升高,负载不断重启。
- 定性:这是什么样的问题?内存泄漏问题?
java程序,跑在linux虚拟机上,监控发现内存不断升高,重启后,又不断升高,直到再次重启。这种属于什么现象,要如何处理?
- 内存泄漏问题与内存溢出问题区别是什么?
规避:面多了加水,水多了加面。
- 加内存,调高堆内存 Xms和Xmx。后面2个分别是什么意思?
建议 初始堆内存大小(-Xms)和最大堆内存大小(-Xmx)设置为相同的值,避免动态调整堆大小带来的性能开销。
这里的性能开销指
- 要消耗计算资源和时间。要重新分配内存空间;
- GC的频率和停顿时间;
- 应用程序不稳定;
- 频繁地调整对OS造成影响,影响性能;
- 如果处理内存泄漏问题
- 这问题放到问小微助手会得到什么答复?
java程序,跑在linux虚拟机上,监控发现内存不断升高,重启后,又不断升高,直到再次重启。这种属于什么现象,要如何处理?
- 出现这种问题如何在节点上搞下文件
- JVisualVM怎么用来分析文件的?
不断创建线程池,完了这些线程池又不会被JVM给GC
GC如何判断哪些对象应该被回收?哪些对象不应该被回收?
为什么在这个场景,不会被回收?
参考.html
- 局部变量new线程池不会被回收吗?
看一段代码 这段代码打出来
- 开头Test代码打出来,换个方法名GC回收的原理
主要看对象的可达性
- 可达性算法
从GCRoot对象(GC根节点对象) 出发,沿着引用有向图上的路径,一个对象一个对象开始遍历,能到达就标个颜色(灰),遍历完的也标个颜色(黑),最后遍历完,没标颜色就是不可达对象,不再会使用到,就要被回收。
- 哪些可以作为GCRoots对象?
- 找Runnable getTask的源码
- 什么是workerQueue
- 如何验证呢
freesion/article/49741215019/
- 找一下解释的原文贴进来
这个线程是live thread吧
证明 线程 -> executorService是可达的
- 打补丁,经常一个java文件build(编译)出来好几个class文件,为什么?
因为非静态内部类持有外部类的引用。
再看下Worker类在哪?
Worker类声明在了ThreadPoolExecutor类的内部
Worker类返回的这个线程对象,是持有 threadPoolExecutor 对象引用的。完了它是一个live thread吧,可以作为GC Root吧,GC Root -> threadPoolExecutor 可达。
- 怎么分析呢?说明下Profile插件用法
- 补一下静态内部类代码
要调用父类的方法必须new一个外部类对象才行
什么道理:没有充分理由就别去创建非静态内部类,为什么?
- 《Effective Java(第三版)》中的第 24 条:静态内部类优于非静态内部类
因为每new一次非静态内部类,就会有指向父类对象的引用。如果外部类有很大的对象时,这是不合理的,你又用不到他,非得去持它的对象干嘛,闲的没事,找OOM吗?
下面其实不需要
- 虚拟机栈
栈帧中局部变量表:存方法参数和方法中定义的局部变量。生命周期是随方法调用结束栈帧销毁而销毁;方法区(又称静态区,存类的静态属性、常态、方法代码)
方法区中类静态属性引用的对象;
方法区中常量(常量池)引用的对象:public static final String/int/long;本地方法栈(转为执行本地方法服务)
本地方法栈中JNI(java与其他语言交互的机制)引用的对象:通过JNI的接口从堆传递到本地方法栈供本地方法使用,被本地方法使用的对象。
本地方法:被Java程序通过JNI调用的非Java语言编写的方法。关键字:native;
Java8 内存模型
线程池最佳实践
参考资料:
.html
正确声明线程池
《华为编程规范》
阿里:
- 补充下华为编程规范如何要求声明线程池的
- 补充阿里编程规范对线程池的要求
- 补充下为什么要这么做?
线程池命名
- 这块应该如何做?
不同类型业务用不同线程池
父子任务的坑:
- 写出代码,问能不能合入?
- 扒一下这个案例,记得画图!
业务背景说下
一个广告的扣费服务
用户:用户——>看到广告——>点击广告
广告主:点击数量——>产生费用——>扣除费用
代码语言:java复制// 线程池声明
bizThreadPool = new newFixedThreadPool(25);
// 执行扣费任务
public Result<Integer> executeDeduct(ChargeInputDTO chargeInput) {
ChargeTask chargeTask = new ChargeTask(chargeInput);
bizThreadPool.execute(() -> chargeTaskBill.execute(chargeTask));
return Result.success();
}
// 扣费任务
public class ChargeTaskBill implements Runnable {
public void execute(ChargeTask chargeTask) {
// 参数校验
verifyInputParam(chargeTask);
// 反作弊校验
executeUserSpam(SpamHelper.userConfigs);
// 执行扣费
handlePay(chargeTask);
// 其他业务动作
...
}
}
// 反作弊校验
public void executeUserSpam(List<SpamUserConfigDO> configs) {
if (CollectionUtils.isEmpty(configs)) {
return;
}
try {
// 反作弊校验 n 个
CountDownLatch latch = new CountDownLatch(configs.size());
for (SpamUserConfigDO config : configs) {
UserSpamTask task = new UserSpamTask(config,latch);
bizThreadPool.execute(task);
}
//阻塞主线程,等n个反作弊校验方法执行完
latch.await();
} catch (Exception ex) {
logger.error("", ex);
}
}
- CountDownLatch 搭配线程池是怎么用的
- 线程池任务添加原理?
队列有哪些?
- 造成死锁的原因有哪些?
- 有没有进一步的优化空间?
- 可用性:秒杀中订单扣费是用的MQ异步吗?
有关闭线程池吗?
案例:线程池创建放在逻辑判断里未关闭
- 写出代码,问能不能合入?
- 写出案例
线程池任务耗时吗?
- 《future超时的坑》 写出代码,问能不能合入?
- 写出案例,会导致什么后果?
重复创建线程池了吗?
重复创建线程池了吗?
创建线程池有没有放到局部变量里!
正确配置线程池参数
如何设置线程池参数?
- 参数应该如何设置呢?
监控线程池状态
假如我们有个线程池,叫xx
正在运行中,各种数据是多少怎么弄?在页面上展示出来
- 用userwebsite代码写个demo,url访问调用这些方法的结果;
总结-《线程池自检清单》
- 画出这张自检清单
动态线程池
- 创建2个线程池,用Map来装,用url请求来处理。
线程池动态调整:
提问
- 如果让你设计一个动态线程池,要支持各种配置中心,不能引入外部jar包,你会怎么设计?
提问:==&mid=2247505057&idx=1&sn=621ebc409b589478e2e05388e079d8c0
DynamicTp:.html
Java内存模型
堆里面会存放哪些?
- 对象:new创建的所有对象;
- 数组对象;
- 类实例对象:类的实力变量(非静态成员变量);
堆转储文件能看到哪些内容?
堆转储文件 heap dump,是JVM在运行时的快照,记录Java堆中对象的状态信息。
用来诊断和分析内存问题,如内存泄漏、内存溢出。
里面包含有
- 所有对象
- 所有类
- GC Roots
- 线程堆栈和本地变量;
阻塞队列
雷军-墨菲定律
雷军演讲提到过得墨菲定律
凡事只要有可能出错,那就一定会出错
如何设置线程池参数
其实关注3个参数就行
corePoolSize、maximumPoolSize、workQueue(队列长度)
IO 密集型任务
I/O密集型的场景在开发中比较常见,比如像 MySQL数据库读写、文件的读写、网络通信等任务。
IO密集型通常设置为 2n+1(n 为 CPU 核数;)
CPU密集型
比如加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务。建议设置为n+1,避免多线程环境下CPU资源带来上下文频繁切换的开销。
有些脱离实际
- 因为机器上肯定不止你一个应用,肯定不止你一个线程池!
- 不同时间段,流量肯定不一样;
所以最好的解决方式——动态化配置
为什么可以支持呢?因为JDK线程池提供了这样的方法
动态更新的工作原理是什么?
动态设置的注意点有哪些?
allowCoreThreadTimeOut 在哪设置?
如何动态指定队列长度?
把 LinkedBlockingQueue 粘贴一份出来
executor.getQueue();
所以,我们可以对线程池进行多维度的监控,比如其中的一个维度就是队列使用度的监控。
当队列使用度超过 80% 的时候就发送预警短信,提醒相应的负责人提高警惕,可以到对应的管理后台页面进行线程池参数的调整,防止出现任务被拒绝的情况。
代码语言:java复制public void setCapacity(int capacity) {
final int oldCapacity = this.capacity;
this.capacity = capacity;
final int size = count.get();
if (capacity > size && size >= oldCapacity) {
signalNotFull();
}
非常小概率处异常。
本文标签: 线程池(I)
版权声明:本文标题:线程池(I) 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1754609491a1704341.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论