学校户网站建设方案,seo电商运营是什么意思,界面交互设计,wordpress 手机页面前言#xff0c;
一次线程池的不当使用#xff0c;导致了现场出现了线程死锁#xff0c;接口一直不返回。而且由于这是一个公共的线程池#xff0c;其他使用了次线程池的业务也一直阻塞#xff0c;系统出现了OOM#xff0c;不过是幸好是线程同事测试出来的#xff0c;没…前言
一次线程池的不当使用导致了现场出现了线程死锁接口一直不返回。而且由于这是一个公共的线程池其他使用了次线程池的业务也一直阻塞系统出现了OOM不过是幸好是线程同事测试出来的没有直接在生产坏境中出现这种事故否则后果不堪设想。
具体情况
我接到一个需求需要在多个excel中根据excel中数据的关联关系拼接出完整的记录然后入库。其实这种情况跟数据库中表情况挺类似的如果将excel必做数据库中的表就是几个表有数据需要根据关联关系写一个查询SQL将查询出来的结果入库到另一张表中。
举个例子虽然不太恰当但是能说明情况 学生excel、学生信息excel、详细住址excel之间的关系是一对一对一一条学生对应一条学生信息一条学生信息对应一条详细住址。现在就是要将这三个excel中的记录拼接成一条完整的记录然后入库每个excel中都有上万条记录。这里是excel不是数据库没法写SQL。感觉此时就像自己来实现SQL的连表逻辑多层循环第一层遍历学生excel的数据拿到一条学生数据之后再遍历第学生信息excel根据学生ID去学生信息exe找找到学生信息记录如果还有一层关联关系就还得套一层循环。
当然这是最原始的想法但是我不想这么做一个表上万条记录再套三层循环效率很低了而且就算三层循环跑完了组装出来的上万条记录也不可能一次性就能入库。所以我采用了线程池我是这么想的
那么多记录使用线程分批处理每个线程处理一批数据每个批次1000条记录相当于每次入库1000条。当根据学生ID拿到一条学生信息记录之后再使用线程池分批去遍历详细住址excel分批寻找找到记录就起来待所有的线程执行完成之后将找到的记录返回去再拼接起来就成了完成的记录。
大概流程如下
task1就是分批处理学生excel拿到每个学生记录再去循环学生信息excel找到唯一的记录进行拼接然后再使用线程池执行task2根据信息ID去分批遍历详细住址excel找到详细住址记录再将其拼接最终拼接成唯一的记录返回入库。
原因分析
写完代码之后我自己造了一些数据进行测试没得问题测试也造了一些数据测试也没发现这个问题。(没有进行大量数据进行性能测试)丢给现场现场同事使用真实数据进行验证的时候出了问题。为啥自测和测试同事测试都没问题而现场同事验证就出了问题呢本质的原因就是数据量自测和测试同事在测试时造的数据数据量都很小一旦数据量大了就会出现问题。
数据量小的时候task1使用线程池中的线程没用使用完线程池中还有剩余的线程所以task1执行到需要条用task2时还有多余的线程去执行task2。而一旦数据量比较大的时候执行到task1时就直接将线程池中所有的线程占用完了线程池中的所有线程都在执行task1然后执行到需要调用task2时又要到线程池中去获取线程结果此时已经没有多余的线程了task1就阻塞了等待线程池中有空余的线程。但线程池中所有的线程都阻塞在调用task2处都在等待就形成了线程死锁。
解决办法
当然出现这个问题说明我们在设计之初就有漏洞最正确的做法应该是设计时就不要让同一个线程池执行父子任务。那既然出现了这个问题该如何解决呢或者说这个情况正确的设计是什么呢我觉得有两个方向
如果系统资源足够那么就再创建一个线程池让task2使用另一个线程池相互独立那么就不会出现线程死锁如果系统资源不够那么task2就不使用线程池进行执行使其单线程跑那么也不会出现线程死锁。
两种方式的比较
如果最初在设计时我更倾向于使用方式2因为task1将所有的线程都占满了那说明线程池的利用率已经是最高了让task2去单线程跑也没有什么不妥。而如果一味的去新建线程池有滥用系统资源的嫌疑。
讲师我现在的情况是代码已经写成了这样了我更倾向于方式2因为那样对我原有的代码改动最小只用将task2提交到另一个线程池就可以了而且我们硬件资源也是足够的。如果采用方式1改动比较大。
示例代码
这种情况是与语言无关的我的主语言是java所以使用java代码写一个示例让java道友有更深刻的认识。
// java代码待补充