it编程 > 编程语言 > Java

Java线程死锁的问题解决

0人参与 2026-03-19 Java

1. 死锁案例

死锁:线程之间互相持有对方的锁,并且等待获取对方持有的锁。

案例如下:我这里直接写的service层代码,没写测试类(测试类直接调用deadlocktest()方法)。

package cn.sh.tools.service.component.lock;
 
import lombok.allargsconstructor;
import lombok.getter;
import lombok.extern.slf4j.slf4j;
import org.springframework.scheduling.concurrent.threadpooltaskexecutor;
import org.springframework.stereotype.component;
 
import javax.annotation.resource;
import java.util.arraylist;
import java.util.comparator;
import java.util.list;
import java.util.concurrent.countdownlatch;
 
/**
 * @description
 * @classname lockcomponent
 * @date 2023/4/28
 * @author sh
 **/
@component
@slf4j
public class lockcomponent {
 
    // 记得在 yml文件中配置线程池相关参数(核心线程数、工作队列大小、最大线程数)。
    @resource(name = "applicationtaskexecutor")
    private threadpooltaskexecutor threadpooltaskexecutor;
 
    // 入参createthreadnum:要创建的线程数。尽量设置个十几二十个,设置的太小可能程序执行太快就发生不了死锁。
    public void deadlocktest(int createthreadnum) {
        // 计数器
        countdownlatch suncdl = new countdownlatch(createthreadnum);
        // 1- 填充数据
        list<deadlockobj> deadlockobjlist = new arraylist<>(createthreadnum);
        /**
         * for循环 创建deadlockobj对象,这里只创建了两种对象。
         * 这里创建两种对象的原因是为了 后面创建的线程互相持有锁。
         */
        for (int i = 0; i < createthreadnum; i++) {
            if (i % 2 != 0) {
                // i 为 奇数时,给 deadlockobj 对象的 a = 1,b = 2。
                deadlockobjlist.add(new deadlockobj(i, 1, 2));
            } else {
                // i 为 偶数时,给 deadlockobj 对象的 a = 2,b = 1。
                deadlockobjlist.add(new deadlockobj(i, 2, 1));
            }
        }
        deadlockobjlist.sort(comparator.comparingint(deadlockobj::getid));
 
        // 循环数据,调用 deadlockinternal()方法,展示死锁情况。
        deadlockobjlist.foreach(deadlockobj -> {
            this.threadpooltaskexecutor.execute(() -> {
                try {
                    suncdl.await();
                } catch (interruptedexception e) {
                    throw new runtimeexception(e);
                }
 
                // 在高并发情况下,必然会出现死锁。
                this.deadlockinternal(deadlockobj);
            });
        });
 
        // 循环将 计数器 减1,当减为0时,上面的线程就开始 真正的并发执行。
        for (int i = 0; i < createthreadnum; i++) {
            suncdl.countdown();
        }
    }
 
    private void deadlockinternal(deadlockobj deadlockobj) {
        /**
         * ① 线程a 持有 integer.valueof(1),线程b 持有 integer.valueof(2)
         * ② 线程a 抢占 integer.valueof(2),但是2被线程b持有。
         *   同时,线程b 抢占 integer.valueof(1),但是1被线程a持有。
         * 线程a 和 线程b 要抢占的锁都被对方持有,所以,必然会出现死锁。
         */
 
        // 第一把锁
        synchronized (integer.valueof(deadlockobj.geta())) {
            // 第二把锁
            synchronized (integer.valueof(deadlockobj.getb())) {
                system.out.println(deadlockobj.getid());
            }
        }
    }
 
    @getter
    @allargsconstructor
    static class deadlockobj {
        integer id;
        int a;
        int b;
    }
 
}

2. 死锁线程查看

2.1 第一步

当 java程序发生死锁时,javavisualvm 的 "线程"标签页 会自动显示红色提示信息:“检测到死锁!生成一个线程dump以获取更多信息”。如下图所示:

javavisualvm 不能很方便的查看到到底是哪几个线程发生了死锁,所以,接下来我们就可以用到 jconsole了。

【备注】:javavisualvm 在jdk8的时候还是自带工具,到jdk11的时候就不是自带的了,但还是可以免费下载和免费试用的。(至于jdk9、10有没有自带不知道,没下载过)。

2.2 第二步

上面一步,javavisualvm 已经【自动】给我们提示出现了【死锁】。这里,我们就可以用 jconsole 来查看了。

死锁 小标签页,我们随便点击一个线程就可以查看对应的 线程快照信息。

到此这篇关于java线程死锁的问题解决的文章就介绍到这了,更多相关java线程死锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

Java 并发编程基础概念与常见问题整理

03-19

Springboot 缓存@Cacheable 的引入和使用

03-19

Spring Boot集成Redis Stream消息队列从入门到实战指南

03-19

Java Arraylist在多线程环境下的问题与解决方案

03-19

RabbitMQ  @RabbitListener 与 @RabbitHandler 的使用区别解析

03-19

Java实现获取两个日期之间的所有日期的开始时间集合

03-19

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论