天天看點

測試并發應用(六)用 FindBugs 分析并發代碼

靜态代碼分析工具是一套通過分析應用源代碼來查找潛在異常的工具。這些工具,例如 checkstyle, pmd, 或者 findbugs,他們有定義極好的實踐(good practices) 規則,然後解析源代碼來查找有沒有違反這些規則。目的是在産品運作之前,更早的找到異常或者修改較差性能的代碼。各種程式設計語言通常提供這樣的工具,java也不例外。分析java代碼的工具之一是 findbugs。 它是開發資源工具,包含了一系列的規則來分析 java concurrent 代碼。

在這個指南,你将學習如何使用工具來分析你的 java concurrent 應用。

準備

怎麼做呢…

按照這些步驟來實作下面的例子:

<code>01</code>

<code>import</code> <code>java.util.concurrent.timeunit;</code>

<code>02</code>

<code>import</code> <code>java.util.concurrent.locks.reentrantlock;</code>

<code>03</code>

<code>04</code>

<code>// 1. 建立一個類,名為 task,擴充 runnable 接口.</code>

<code>05</code>

<code>public</code> <code>class</code> <code>task </code><code>implements</code> <code>runnable {</code>

<code>06</code>

<code>    </code><code>// 2. 聲明一個 reentrantlock 屬性,名為 lock.private</code>

<code>07</code>

<code>08</code>

<code>    </code><code>reentrantlock lock;</code><code>// 3. 實作類的構造函數。public</code>

<code>09</code>

<code>10</code>

<code>    </code><code>task(reentrantlock lock) {</code>

<code>11</code>

<code>        </code><code>this</code><code>.lock = lock;</code>

<code>12</code>

<code>    </code><code>}</code>

<code>13</code>

<code>14</code>

<code>    </code><code>// 4. 實作run() 方法。擷取lock的控制,讓線程休眠2秒再釋放lock。</code>

<code>15</code>

<code>    </code><code>@override</code>

<code>16</code>

<code>    </code><code>public</code> <code>void</code> <code>run() {</code>

<code>17</code>

<code>        </code><code>lock.lock();</code>

<code>18</code>

<code>        </code><code>try</code> <code>{</code>

<code>19</code>

<code>            </code><code>timeunit.seconds.sleep(</code><code>1</code><code>);</code>

<code>20</code>

<code>            </code><code>lock.unlock();</code>

<code>21</code>

<code>        </code><code>} </code><code>catch</code> <code>(interruptedexception e) {</code>

<code>22</code>

<code>            </code><code>e.printstacktrace();</code>

<code>23</code>

<code>        </code><code>}</code>

<code>24</code>

<code>25</code>

<code>26</code>

<code>    </code><code>// 5.建立例子的主類通過建立一個類,名為 main 并添加 main()方法。</code>

<code>27</code>

<code>    </code><code>public</code> <code>static</code> <code>class</code> <code>main {</code>

<code>28</code>

<code>29</code>

<code>        </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>

<code>30</code>

<code>            </code><code>// 6. 聲明并建立一個 reentrantlock 對象,名為 lock.</code>

<code>31</code>

<code>            </code><code>reentrantlock lock = </code><code>new</code> <code>reentrantlock();</code>

<code>32</code>

<code>            </code><code>// 7. 建立10個 task 對象和10個線程來執行這些任務。調用 run() 方法開始線程。</code>

<code>33</code>

<code>            </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; </code><code>10</code><code>; i++) {</code>

<code>34</code>

<code>                </code><code>task task = </code><code>new</code> <code>task(lock);</code>

<code>35</code>

<code>                </code><code>thread thread = </code><code>new</code> <code>thread(task);</code>

<code>36</code>

<code>                </code><code>thread.run();</code>

<code>37</code>

<code>            </code><code>}</code>

<code>38</code>

<code>39</code>

<code>        </code> 

<code>40</code>

<code>41</code>

<code>}</code>

8. 把項目導出為 jar 檔案。命名為 recipe8.jar。使用你的ide的菜單選項,或者使用javac 和 jar 指令來編譯并壓縮你的應用。

9. start the 開始使用 findbugs standalone 應用 在windows 運作 findbugs.bat 指令或者在 linux 使用 findbugs.sh 指令。

10. 菜單欄的 file 菜單的new project 選項來建立新的項目。

測試并發應用(六)用 FindBugs 分析并發代碼

11. findbugs 應用展示了項目的配置視窗。在project name 區域顯示文字 recipe08。在 classpath 的分析區域加入了項目的jar檔案并在 source 路徑區域加入了例子的源代碼的路徑。詳見以下裁圖:

測試并發應用(六)用 FindBugs 分析并發代碼

12. 單擊 analyze 按鈕來建立新的項目并分析它的代碼。

13. the findbugs 應用顯示了代碼的分析結果。在這個例子中,它找到了2個bugs。

14. 單擊其中一個bug,你可以在右手邊的版面看到 bug 的源代碼和在螢幕的下端的版面有bug的描述。

它是如何工作的…

以下的截圖是findbugs的分析結果:

測試并發應用(六)用 FindBugs 分析并發代碼

在這個應用中,分析檢查到了下面2個潛在的bugs:

一個是在 task 類的run()方法中。如果 if an interruptedexeption 異常被抛出,由于任務不會執行unlock()方法就不會釋放鎖。這樣就可能在應用中形成deadlock的狀況。

另一個是在main類的 main() 方法中,因為你直接調用線程的 run() 方法,但是還沒有調用 start() 方法來開始執行線程。

如果你輕按兩下任何一個bugs,就可以看到它的具體資訊。隻要你在配置這個項目中引用了source-code,你就可以看到bug被檢查到的源代碼。以下截圖向你展示了一個例子:

測試并發應用(六)用 FindBugs 分析并發代碼

更多…

要注意的是findbugs 隻能檢查一些問題情況(無論是否與并發代碼相關)。例如,如果你删除 task 類中的 run()方法中的 unlock()調用,然後重新分析,findbugs 是不會警告你在task裡還有個lock你還沒有解放。

使用靜态代碼分析工具可以幫助你提升你的代碼,但是不要期望它可以找到你代碼中的所有bugs。

參見

第八章,測試并發應用: 配置netbeans來調試并發代碼