1. 程式人生 > 其它 >idea以任意順序debug多執行緒程式

idea以任意順序debug多執行緒程式

@

目錄
在idea中使用debug可以讓多個執行緒以任意順序執行,先介紹一下基礎知識,然後介紹具體做法。

1 debug 兩類 Supspend

在斷點處右鍵,可以看到Suspend分兩類,一類是All,一類是Thread。當某個執行緒到達斷點處會觸發Suspend,All會使得所有執行緒都暫停,Thread只會使當前觸發的執行緒暫停,其他執行緒不受影響。

在idea中使用debug可以讓多個執行緒以任意順序執行,先介紹一下基礎知識,然後介紹具體做法。

以下面的程式碼為例,有3個MyThread執行緒以及一個主執行緒main。3個執行緒分別睡眠 1/2/3 秒,主執行緒睡眠 5 秒。下面分三種情況檢視結果:

  1. 正常執行,執行完的順序為 1, 2, 3, main
  2. 在斷點1處打斷點,設定為 All,線上程1觸發後所有執行緒均暫停,可以通過Resume繼續執行下一個斷點,正常情況應該是3次Resume才能結束,但在有些時候idea會提示 skipped breakpoint at because it happened inside debugger evaluation,會跳過一些斷點,這可能是ide本身的問題,可以在Settings->Build ... ->Debugger->Data Views->Java中 取消 Enable 'toString()' object view。
  3. 在斷點1處打斷點,設定為 Thread,3個子執行緒都會在斷點處暫停,main執行緒沒有暫停,會先執行完。
package org.example;

public class Test{
    public static void main(String arg[]){
        MyThread thread1 = new MyThread(1);
        MyThread thread2 = new MyThread(2);
        MyThread thread3 = new MyThread(3);

        thread1.setName("Thread 1");
        thread2.setName("Thread 2");
        thread3.setName("Thread 3");

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

        try {
            Thread.sleep(1000*5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主執行緒完成");
    }

    private static class MyThread extends Thread {
        private int num;
        public MyThread(int num) {
            this.num = num;
        }
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            try {
                Thread.sleep(1000*num);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"斷點1"); //斷點1
            System.out.println(Thread.currentThread().getName()+"斷點之間執行");
            System.out.println(Thread.currentThread().getName()+"斷點2"); //斷點2       
        }
    }

2 按照順序執行執行緒

在子執行緒打兩個Thread斷點,通過Frames控制子執行緒的執行順序,假設斷點之間的執行順序為3, 2, 1, 2, 1, 3。其中第一次執行從斷點1開始,執行到斷點2之前,第二次執行會執行斷點2並結束。

如果感覺不好理解,可以將MyThread換成三個不同的類分別對應三個執行緒,在三個類中分別打斷點。這裡我不再替換。

debug執行,稍等一會,三個執行緒都會到第一個斷點停下,此時未有任何輸出,注意在左下角Frames的選單,點開,會發現三個執行緒都在Frames內,這說明三個執行緒都已經暫停,有時候下拉框會有main,但其實main不會暫停。

想先執行Thread 3,則在下拉框選擇Thread 3,點一下Resume,此時Thread 3的第一個斷點和斷點之間的程式碼執行,Thread 3暫停在第二個斷點上,其他暫停的執行緒不受影響。

對應的後續執行順序是,切換到Thread 2/1/2/1/3,每次切換都Resume一次。

總結:想讓哪個執行緒先執行就在下拉框切換到相應的執行緒,並Resume,則該執行緒執行到下一個斷點,如果沒有下一個斷點則會一直執行直到結束。此時,其他暫停的執行緒會一直暫停等待。

這樣的做法可以推廣到多個執行緒,對於需要暫停的執行緒都打上斷點即可,每個執行緒可以打多個,方便控制執行順序。對於不需要暫停的執行緒可以不打斷點,就像這裡的main執行緒一樣。

3 Condition的使用

另外如果只想讓某個執行緒在斷點處停止,可以使用斷點的Condition,如上面的程式碼中只想讓第一個執行緒暫停,則可以在斷點處右鍵,在Condition中填入Thread.currentThread().getName().equals("Thread 1");