1. 程式人生 > >在多執行緒環境中呼叫native方法

在多執行緒環境中呼叫native方法

這幾天忙著寫一個用於資料同步的Java程式,在這裡遇到了一個令人頭大的問題。
問題是這樣:我的資料同步程式要同時跑四個執行緒,在其中的一個執行緒中,要做一個MD5的檔案校驗工作。這個MD5的校驗是要通過呼叫一個dll來實現,這個dll(名字叫做MD5Operation.dll)是用於對檔案內容進行MD5運算的,目的是用於做伺服器端和客戶端的檔案校驗。

類MD5Tool的原始碼如下:

package com.hode.util;

public class MD5Tool
{
     public static native String hMd5( String szFilePath);  
     static
     {
           System.loadLibrary( "MD5Operation" );
     }
}

我聲明瞭一個靜態的本地方法hMD5,這樣我在程式中就可以直接用MD5Tool.hMD5(filePathName)來呼叫了,經過我的簡單測試,程式執行正常。
測試程式碼如下:

package com.hode.util

public class TestMD5
{
     public static void main(String[] args)
     {
          String filePathName = "C://my music//heal the world.mp3";
          String fileMD5Str = MD5Tool.hMD5(filePathName);
          System.out.println("fileMD5Str=" + fileMD5Str);
     }
}

但是當我把它拿到資料同步的程式中執行,當程式執行到MD5Tool.hMD5(filePathName)這條語句的時候,莫名其妙的終止了,而且不會丟擲任何異常,這實在讓人看不懂。找了半天的原因,也找不出什麼問題,因為畢竟呼叫MD5的程式碼就那麼幾行,把它翻來覆去折騰幾遍還是那個樣子。我真的有點搞不定了,這時Neil拿來一本《 JAVA執行緒 》,他找到一頁關於呼叫native方法的相關問題,書中說道,在多執行緒的環境中,呼叫native方法時,要宣告成synchronized static的,否則會出現問題而導致執行緒終止。嘿嘿!有點意思了,我趕忙將程式碼改了過來,我的程式碼變成了:

package com.hode.util;

public class MD5Tool
{
     public synchronized static native String hMd5( String szFilePath);  
     static
     {
           System.loadLibrary( "MD5Operation" );
     }
}

再次執行,結果讓人失望,程式仍然會終止!到底問題出在哪裡??我有點灰心了... ...

既然《JAVA 執行緒》中已經說明了,在多執行緒的環境下呼叫native方法可能會出問題,那麼是不是因為在子執行緒中載入dll的時候會有問題呢?不試不知道,一試嚇一跳,我把dll的載入放到了主執行緒中,然後在子執行緒中進行呼叫,程式碼簡略如下:

package com.hode.sync.thread;

import com.hode.util.MD5Tool;

public class MainThread extends Thread
{
     private MD5Tool myMD5Tool = new MD5Tool();   //在主執行緒中載入dll
    
     .... .... ....

     public static void main(String[] args)
     {
           .... .... ....

          SubThread1 T1 = new SubThread1();
          SubThread1.run();

            .... .... ....
     }
}

public class SubThread1 extends Thread
{
     public void run()
     {
           .... .... ....

          String filePathName = "C://my music//heal the world.mp3";
          String fileMD5Str = MD5Tool.hMD5(filePathName); //在子執行緒中呼叫hMD5方法
          System.out.println("fileMD5Str=" + fileMD5Str);

          .... .... ....
     }
}

執行成功啦!哦,原來是這樣,在呼叫native方法的時候要注意以下幾點:
(1) 在多執行緒的同時執行的時候,最好將native方法宣告成synchronized static。
(2) dll的載入要在主執行緒中進行,但可以在子執行緒中呼叫。