在IntelliJ IDEA中多线程并发代码的调试方法详解
作者:字母哥博客 发布时间:2022-01-09 03:05:45
通常来说,多线程的并发及条件断点的debug是很难完成的,或许本篇文章会给你提供一个友好的调试方法。让你在多线程开发过程中的调试更加的有的放矢。
我们将通过一个例子来学习。在这里,我编写了一个多线程程序来计算此数学问题:100! + 100000!
。即:100的阶乘 + 100000的阶乘。
数学不好的同学看这里,100 阶乘就是:1 * 2 * 3 * …… * 100 = ? ,简写为100!
import java.math.BigInteger;
public class MathProblemSolver {
//开启两个线程
public static void main(String arg[]){
//第一个线程计算 100!
FactorialCalculatingThread thread1 = new FactorialCalculatingThread(100);
//第二个线程计算 100000!
FactorialCalculatingThread thread2 = new FactorialCalculatingThread(100000);
thread1.setName("Thread 1");
thread2.setName("Thread 2");
thread1.start();
thread2.start();
try {
thread1.join(); //线程Jion,以使主线程在“线程1”和“线程2”都返回结果之前不会进一步执行
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
BigInteger result = thread1.getResult().add(thread2.getResult());
System.out.println("将两个线程的计算结果相加等于:" + result);
}
//用于阶乘计算的线程类
private static class FactorialCalculatingThread extends Thread {
private BigInteger result = BigInteger.ONE;
private long num;
public FactorialCalculatingThread(long num) {
this.num = num;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始阶乘的计算:" + num);
factorialCalc(num);
System.out.println(Thread.currentThread().getName() + "执行完成");
}
//数的阶乘计算方法
public void factorialCalc(long num) {
BigInteger f = new BigInteger("1");
for (int i = 2; i <= num; i++)
f = f.multiply(BigInteger.valueOf(i));
result = f;
}
public BigInteger getResult() { return result; }
}
}
上面的代码解释
开启两个线程,“Thread 1”计算(100!)和“Thread 2”计算(100000!)
在main()方法中启动两个线程,然后调用
thread1.join()
和thread2.join()
,以使主线程在“线程1”和“线程2”都返回结果之前不会进一步执行。最后将两个线程的计算结果相加,得到
100! + 100000!
下面就让我们使用IntelliJ IDEA工具来调试这段多线程的代码。
Frames 与 Thread 面板
调试工具窗口的“Frames”面板包含一个下拉菜单。它的关注点在:由于断点而导致暂停的线程,并显示这些线程的调用堆栈信息。在下图中,断点位于main()方法中如图所示的位置,Frame向我们显示了主线程的调用堆栈。
如果要检查其他线程的调用堆栈,则可以从下拉列表中进行选择。
Thread面板显示当前处于活动状态的所有线程。参考上面的代码,我在thread1.join()
添加了一个断点。当应用程序在该断点处暂停时,我们应该在此窗格中至少看到三个线程-“main”,“Thread 1”和“Thread 2”(请看下面的屏幕截图)。您可以双击每个线程以观察其调用堆栈。
条件断点-只挂起符合条件的线程
假设我正在解决该程序中的错误,并且我只需要在“Thread 2”开始运行时就暂停执行。这表明我需要在FactorialCalculatingThread的run()方法的第一行上添加一个断点。因为我们开启的两个线程使用的是同一段代码,所以我们会遇到一个问题-使用该段代码的所有线程遇到断点都将被挂起,包括应用程序的“Thread 1”和“Thread 2”。我不希望两个线程都暂停。该怎么做?
我们可以使用条件断点功能。添加断点后,右键单击它,选中“suspend”并选择“Thread”。然后我们添加条件currentThread().getName().equals("Thread 2")
,如下面的屏幕快照所示。此条件确保调试器仅在当前线程的名称为“Thread 2”时才暂停当前线程:
现在执行调试程序,当应用暂停时,仅“Thread 2”被暂停。您可以通过以下步骤确认“Thread 1”已执行并且没有被挂起:
1.在控制台中,您可以通过日志来验证“Thread 1”已运行并退出。
2.在“Thread”面板中,可以看到此时已经没有“Thread 1”,已经运行完成了!
在不同的IDE版本中,配置条件断点的方式可能有所不同。但是关键思想是要意识到这些功能的存在并加以使用。
来源:https://www.cnblogs.com/zimug/p/13439156.html


猜你喜欢
- C# 中 PadLeft ,PadRight的用法简单来说就是给字符串实现补位。如:String.PadLeft(5,'0'
- 1. 线程转储简介线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。线程转储一般使用文本格式, 可以将其保存到文本文
- 什么是ApplicationContext?它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些。 App
- Android application捕获崩溃异常怎么办?通用 application1、收集所有 avtivity 用于彻底退出应用2、捕
- 本文实例为大家分享了C#仿微信红包功能的具体代码,供大家参考,具体内容如下Program.cs代码:class Program { &nbs
- dataGridView动态绑定数据1.动态绑定DataTable数据DataGridView dgv = new DataGridView
- 为哪些方法代理?实现自己 * ,首先需要关注的点就是,代理对象需要为哪些方法代理? 原生JDK的 * 的实现是往上抽象出一层接口,让目标
- 微信朋友圈上面的图片封面,QQ空间说说上面的图片封面都有下拉反弹的效果,这些都是使用滚动条实现的。下拉,当松开时候,反弹至原来的位置。下拉时
- 前言在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去
- 先看下这个问题的背景:假设有一个spring应用,开发人员希望自定义一个注解@Log,可以加到指定的方法上,实现自动记录日志(入参、出参、响
- Recyclerview现在基本已经替代Listview了,RecyclerView也越来越好用了 当我们有实现条目的拖拽排序和
- 前言在Java中,Range方法在IntStream和LongStream类中都可用。在IntStream类中,它有助于返回函数参数范围内I
- 想要实现无限轮播,一直向左滑动,当到最后一个view时,会滑动到第一个,无限…可以自己写ViewPager然后加handler先实现自动滚动
- XML假如有这样一个XML格式的数据:<?xml version="1.0" encoding="utf
- 本来就是基础知识,不能丢的太干净,今天竟然花了那么长的时间才写出来,记一下。有如下的一颗完全二叉树:先序遍历结果应该为:1 2&
- 限流器算法目前常用限流器算法为两种:令牌桶算法和漏桶算法,主要区别在于:漏桶算法能够强行限制请求速率,平滑突发请求,而令牌桶算法在限定平均速
- 这是一个运用网格布局来做的简易计算器,可能没有那么美观,大家可以继续完善首先先看看成果吧首先先建一个新的Project Calculator
- 笔者近2天在 Android Studio上玩了一下百度地图,碰到了常见的"230错误 APP Scode校验失败",下
- 尝试了各种防止中文乱码的方式,但是还是乱码;最后还是细节问题导致;解决方式:以及俩种方式是百度的,我的问题不是这俩块1.在requestMa
- 前言代理模式,我们这里结合JAVA的静态代理和 * 来说明,类比Spring AOP面向切面编程:增强消息,也是代理模式。而我们的静态代理