Java程序关联的CPU打满100%一般都是程序编写不规范,引发的死循环造成。为什么HashMap的组装数据及调用会造成死循环呢,这里需要从HashMap的底层数据结构分析原因。
数组 + 链表 + 红黑树
- public Map<String,Object> selectByName(List<String> nameList) {
- Map<String,Object> dataMap = new HashMap();
- if (CollUtil.isNotEmpty(dataList)){
- dataList.parallelStream().forEach(item->{
- //业务处理
- if (StringUtils.isNotEmpty(TypeVO.getType())){
- dataMap.put(item.getName(),TypeVO);
- }
- });
- }
- return dataMap;
- }
- void transfer(Entry[] newTable) {
- Entry[] src = table;
- int newCapacity = newTable.length;
- for (int j = 0; j < src.length; j++) {
- Entry<K,V> e = src[j];
- if (e != null) {
- src[j] = null;
- do {
- Entry<K,V> next = e.next;
- int i = indexFor(e.hash, newCapacity);
- e.next = newTable[i];
- newTable[i] = e;
- e = next;
- } while (e != null);
- }
- }
- }
问题就出现在了while (e != null),从上面的代码看来,每一个线程进来都先执行dataMap = new HashMap();这个时候dataMap是空的,所以在执行下面的操作的时候进入了某一个不可以随意更改状态的代码中,再加上高并发,一直被new HashMap(),while一直被执行,变成了死循环。cpu就瞬间飙升到100%,一直持续到请求数降低的时候。
重构问题代码,多线程并发扩容时就会出现环形引用的问题,从而导致死循环的出现,一直死循环就会导致 CPU 运行 100%,所以在多线程使用时,我们需要使用 ConcurrentHashMap 来替代 HashMap,ConcurrentHashMap是线程安全的Map,适合在多线程环境下稳定运行。
- public ConcurrentHashMap<String,Object> selectByName(List<String> nameList) {
- ConcurrentHashMap<String,Object> dataMap = new ConcurrentHashMap();
- if (CollUtil.isNotEmpty(dataList)){
- dataList.parallelStream().forEach(item->{
- //业务处理
- if (StringUtils.isNotEmpty(typeVO.getType())){
- dataMap.put(item.getName(),typeVO);
- }
- });
- }
- return dataMap;
- }
top -c
top -Hp <PID>
printf "%x\n" <TID>
jstack <PID> | grep <16进制的TID> -A 30
- 1.top -c 查出cpu使用率最高进程PID为127387
- 2.top -Hp 127387 查出线程使用率最高TID为128739
- 3.printf "%x\n" 128739 查出TID的16进制为1f529
- 4.jstack 127387 | grep 1f529 -A 30 查出堆栈信息,问题代码