在多執行緒環境中呼叫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的載入要在主執行緒中進行,但可以在子執行緒中呼叫。