如何調試多線程的程序?

> Junit本身是不支持普通的多線程測試的,這是因為Junit的底層實現上,是用System.exit退出用例執行的,主線程終止jvm都停了,其他線程肯定執行不了了(具體分析查看源碼org.junit.runner.JUnitCore)。

# 文檔

官網:http://groboutils.sourceforge.net

# 示例

```

net.sourceforge.groboutils

groboutils-core

5

```

```

public class ThreadJunitDemo {

private static final int THREAD_COUNT = 10;

@Test

@Repeat(1)

public void testThreadJunit() throws Throwable {

try {

//Runner數組,相當於並發多少個

TestRunnable[] trs = new TestRunnable[THREAD_COUNT];

for (int i = 0; i < THREAD_COUNT; i++) {

trs[i] = new TestRunnable() {

@Override

public void runTest() throws Throwable {

commMethod();

}

};

}

// 用於執行多線程測試用例的Runner,將前面定義的單個Runner組成的數組傳入

MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);

// 開發並發執行數組裡定義的內容

mttr.runTestRunnables();

} catch (Throwable e) {

e.printStackTrace();

}

}

private void commMethod() throws Exception {

System.out.println("===" + Thread.currentThread().getId() + "begin to execute ...");

for (int i = 0; i <10; i++) {

int a = i*5;

System.out.println(a);

}

System.out.println("===" + Thread.currentThread().getId() + "end to execute ...");

}

}

```

## TestRunnable

表示一個測試線程,實例需要實現該類的runTest()方法,在該方法中寫自己用的測試代碼。

## MultiThreadedTestRunner

表示需要測試的線程,相當與一個ExecuteService,可以用來執行TestRunnable,構造函數需要傳入TestRunnable數組。

調用MultiThreadedTestRunner.runTestRunnables() 方法啟動測試線程,開始執行測試。

## TestMonitorRunnable

表示監控線程,可以讓每一個TestRunnable對應一個TestMonitorRunnable,在TestMonitorRunnable中監控TestRunnable,TestMonitorRunnable是TestRunnable的子類。

# 總結

GroboUtils使得擴展Java測試變得可能,常常被用於多線程測試,整體單元測試,代碼覆蓋工具。接下來,根據文章的demo去測試一下吧。



如何調試多線程的程序

程序的線程模型應該能在一張 A4 紙上畫出來,有哪些線程,幹什麼活,各路消息來了經過哪些處理步驟,涉及哪些線程,會訪問哪些共享數據,等等。

這樣就算最初的作者離開團隊,後面的維護者也不會輕易破壞這個設計。

要知道,一個看似無害的局部代碼修改,有可能造成 data race,如果混過了code review,那麼就埋雷了,輕則程序崩潰,重則破壞數據。理解程序的線程設計,才能最大限度地防止這一情況的出現。

最後,動態和靜態的分析工具也可以派上用場,例如 Valgrind、ThreadSanitizer。



推薦閱讀:

抽象能力決定編程能力
學編程有前途嗎?
有哪些有趣又優美的編程語言?

TAG:編程語言 | 編程 | 操作系統 | C | 多線程 |