JNI一些坑
pthread創(chuàng)建的子線程沒有 _JNIEnv
因?yàn)開JNIEnv 是根據(jù)線程相關(guān)的,所以pthread創(chuàng)建的native線程必須要調(diào)用JavaVMd->AttachCurrentThread(&env,NULL)方法綁定該線程到虛擬機(jī),然后再線程結(jié)束的時(shí)候調(diào)用DetachCurrentThread()方法解除綁定
void *connect(void *arg) {
SokcetClient *client = static_cast<SokcetClient *>(arg);
_JNIEnv *env;
JavaVM *vm= client->getJavaVM();
client->getJavaVM()->AttachCurrentThread(&env, NULL);
sockaddr_in in;
bzero(&in, sizeof(in));
in.sin_port = htons(client->getPort());
in.sin_addr.s_addr = inet_addr(client->getIp());
in.sin_family = AF_INET;
int result = connect(client->getSocketFtd(), reinterpret_cast<const sockaddr *>(&in),
sizeof(in));
if (result < 0) {
LOGV(" ip = %s | port = %d", client->getIp(), client->getPort());
LOGV("socket connect error result = %d", result);
jmethodID errorId = env->GetMethodID(client->getJclass(),"connectFailed","()V");
env->CallVoidMethod(client->getJobj(),errorId,NULL);
return NULL;
}
jmethodID id = env->GetMethodID(client->getJclass(), "connectSuccess", "()V");
env->CallVoidMethod(client->getJobj(), id, NULL);
client->setConnect(true);
client->receiveMsg();
client->getJavaVM()->DetachCurrentThread();
return NULL;
}
子線程調(diào)用FindClass查找自定義的類為NULL
這是因?yàn)橥ㄟ^AttachCurrentThread附加到虛擬機(jī)的線程在查找類時(shí)只會通過系統(tǒng)類加載器進(jìn)行查找,不會通過應(yīng)用類加載器進(jìn)行查找,因此可以加載系統(tǒng)類,但是不能加載非系統(tǒng)類,如自己在java層定義的類會返回NULL。
env->FindClass("xxx/xxx/xxx");//在子線程這樣調(diào)用是會返回NULL
env->FindClass("java/lang/String");//ok
目前本人的解決辦法是,在主線程時(shí)去findClass然后當(dāng)做global保存起來
//下邊在主線程執(zhí)行
jclass cls = env->FindClass("xxx/xxx/xxx");
jclass globalCls = static_cast<jclass>(env->NewGlobalRef(cls));//一定要使用NewGlobalRef
這個(gè)地方一定要使用NewGlobalRef 將它保存,因?yàn)镴NI默認(rèn)的生命周期只有方法體內(nèi),這個(gè)方法執(zhí)行完,就會被回收。所以用把它保存成全局引用 然后再不用的時(shí)候 調(diào)用方法釋放掉
env->DeleteGlobalRef(globalCls);
線程運(yùn)行完會崩潰
pthread創(chuàng)建完的線程運(yùn)行完會Crash,這是因?yàn)樗怯蟹祷刂档模。。。↗ava寫習(xí)慣之后完全不會注意這一點(diǎn)。)
void* run(void *args){
///省略很多代碼
return NULL //這句話一定要寫。如果沒有返回值就返回NULL
}
void test(){
pthread threadId;
pthread_create(&threadId,NULL,run,NULL);//這個(gè)run的方法體會返回void*的返回值
}
線程的回收
pthread創(chuàng)建的線程運(yùn)行完如果不進(jìn)行回收會一直占用一些資源,可以在線程運(yùn)行時(shí)調(diào)用方法pthread_detach(pthread_self()),這樣它會再運(yùn)行完進(jìn)行回收。也可以使用join方法,具體可以查資料
void* run(void *args){
///省略很多代碼
pthread_detach(pthread_self())//釋放掉資源,一定要在運(yùn)行的方法體內(nèi)執(zhí)行pthread_self()會獲取當(dāng)前的線程Id
return NULL
}
void test(){
pthread threadId;
pthread_create(&threadId,NULL,run,NULL);
}
Java的ByteBuffer.allocateDirect
public static ByteBuffer allocateDirect(int capacity)分配新的直接字節(jié)緩沖區(qū)。
新緩沖區(qū)的位置將為零,其界限將為其容量,其標(biāo)記是不確定的。無論它是否具有底層實(shí)現(xiàn)數(shù)組,其標(biāo)記都是不確定的。
參數(shù):
capacity - 新緩沖區(qū)的容量,以字節(jié)為單位
allocateDirect方法直接使用操作系統(tǒng)來分配Buffer。因而它將提供更快的訪問速度。與native交互會有更高的執(zhí)行速度。但是在使用的時(shí)候發(fā)現(xiàn)他會在byte[]頭部和尾部會多加幾個(gè)字節(jié),導(dǎo)致數(shù)據(jù)異常。暫時(shí)未發(fā)現(xiàn)為什么會這樣。
與之對應(yīng)的還有一個(gè)allocate方法。這個(gè)方法可以正常使用。
Java中的byte在C中怎么處理
眾所周知 Java中的byte是一個(gè)字節(jié),在C中只占一個(gè)字節(jié)的只有char。在調(diào)用到j(luò)ni中byte會被轉(zhuǎn)為jbyte ,這個(gè)是一個(gè)typedef具體定義如下
typedef int8_t jbyte;
所以對應(yīng)的C類型就是int8_t。其實(shí)int8_t也是一個(gè)typedef
typedef __int8_t int8_t;
___int8_t也是一個(gè)typedef
typedef signed char __int8_t;
如何將char[4]轉(zhuǎn)成一個(gè)int32_t的數(shù)字
char header[4];
int number = (header[0]<<24)|(header[1]<<16)|(header[2]<<8)|header[3]-11;
利用位用算:
? 第一位左移24位 XXXXXXXX 00000000 00000000 00000000
? 第二位左移16位 00000000 XXXXXXXX 00000000 00000000
? 第三位左移8位 00000000 00000000 XXXXXXXX 00000000
? 第四個(gè)保持不變 00000000 00000000 00000000 XXXXXXXX
然后將上邊4個(gè)進(jìn)行按位與操作 就是
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
這樣就變成一個(gè)int型的整數(shù)。
一個(gè)int32_t的數(shù)字轉(zhuǎn)為1個(gè)char[4]
char header[4];
int32_t number= X;
header[0] = number>>24&0xFF;
header[1] = number>>16&0xFF;
header[2] = number>>8&0xFF;
header[3] =number&0xFF;
首先一個(gè)整數(shù)他表示為
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
首8位就是向右移24位然后就變成了
? 00000000 00000000 00000000 XXXXXXXX
然后與0xFF進(jìn)行&(同位均為1就是1 否則就是0)運(yùn)算
00000000 00000000 00000000 XXXXXXXX
? &
? 00000000 00000000 00000000 11111111
這就就會取到前8位的數(shù)。
然后第二個(gè)8位就右移16位然后與0xFF進(jìn)行&
00000000 00000000 XXXXXXXX XXXXXXXX
? &
? 00000000 00000000 00000000 11111111
這樣就能取到第二個(gè)8位
剩下的以此類推。