返回

千万不要在方法上打断点!有大坑!

后端

千万不要在方法上打断点!有大坑!

开发中,打断点是非常常用的一个调试手段,它能让我们快速定位到程序出错的位置,并查看变量的状态。但在使用打断点时,我们也要注意一些坑,否则会让我们陷入不必要的麻烦。

打断点导致死锁

当我们在多线程程序中使用打断点时,可能会遇到死锁问题。这是因为当一个线程被中断时,其他线程可能正在等待它的锁,导致所有线程都无法继续执行。

例如,在以下代码中,如果我们在 thread1 上设置了断点,那么 thread2 将永远无法获得 lock

Object lock = new Object();

Thread thread1 = new Thread(() -> {
    synchronized (lock) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});

Thread thread2 = new Thread(() -> {
    synchronized (lock) {
        System.out.println("thread2");
    }
});

thread1.start();
thread2.start();

打断点导致数据不一致

在多线程程序中,使用打断点还可能会导致数据不一致。这是因为当一个线程被中断时,其他线程可能正在修改数据,导致数据处于不一致的状态。

例如,在以下代码中,如果我们在 thread1 上设置了断点,那么 thread2 可能在 thread1 修改 data 之前就打印了 data

int data = 0;

Thread thread1 = new Thread(() -> {
    synchronized (this) {
        data = 1;
    }
});

Thread thread2 = new Thread(() -> {
    synchronized (this) {
        System.out.println(data);
    }
});

thread1.start();
thread2.start();

避免打断点导致问题的建议

为了避免在使用打断点时遇到问题,我们可以采取以下建议:

  • 尽量避免在多线程程序中使用打断点。 如果必须使用,请确保不会导致死锁或数据不一致。
  • 如果需要在多线程程序中使用打断点,请使用条件断点。 条件断点允许我们在满足特定条件时才中断程序,这样可以避免在不必要的时候中断程序。
  • 使用调试器中的其他调试工具。 除了打断点之外,调试器还提供了其他调试工具,例如单步执行、查看变量值等。这些工具可以帮助我们更灵活地调试程序。

问题的解决方式

上周遇到的那个问题,就是因为在多线程程序中使用了打断点导致的。当时我在调试一个死锁问题,在 thread1 上设置了断点。结果 thread2 一直无法获得 lock,导致程序死锁。

解决这个问题的方法很简单,就是去掉打断点 。去掉打断点后,程序就可以正常运行了。

这个解决方式让我很无语,因为我当时完全没有意识到是打断点导致的问题。我以为是代码出了问题,所以 spent 了好几个小时在代码里找 bug。结果最后发现问题竟然是因为一个打断点,真是浪费时间。

所以,在使用打断点时一定要注意,不要在多线程程序中滥用打断点。否则,你可能会陷入不必要的麻烦中。