pthread.h可以在NDK环境里创建子线程,并对线程能够做出互斥所、等待、销毁等控制。
1. 开启和销毁线程
开启线程
pthread_t pthread;
pthread_create(&pthread, NULL, threadFunc, (void *) "");
pthread_create函数能够创建线程,运行了这个函数线程就会运行起来,执行第三个参数所代表的函数
参数1 pthread_t* pthread 线程句柄
参数2 pthread_attr_t const* 线程的一些属性,一般为NULL
参数3 void* (__start_routine)(void) 线程具体执行的函数
参数4 void* 传给线程的参数
等待线程
如果开启线程只有一个可以不写等待线程完成和返回参数,但是如果有多个线程这个就必须要写,不写的话只会运行第一个线程
int retvalue;
pthread_join(pthread,(void**)&retvalue);
if(retvalue!=0){
LOGD("thread error occurred");
}
线程执行函数
void* threadFunc(void* arg) {
LOGD("execute native sub thread");
// 退出线程,返回结果,这里必须要执行,不然程序会报错
pthread_exit((void*)2);
return (void*)0;
}
完整示例
#include "pthread.h"
#include "logger.h"
void* threadFunc(void* arg) {
char* str = (char*) arg;
LOGD("execute native sub thread");
LOGD("params: %s", str);
// 退出线程,这里必须要现在,不然重新会报错
pthread_exit((void*)2);
return (void*)0;
}
extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThread(JNIEnv *env,
jclass clazz) {
pthread_t pthread;
jint ret = pthread_create(&pthread, NULL, threadFunc, (void*) "this is params");
LOGD("pthread_create ret=%d", ret);
// 等待线程方法执行完成返回结果,注意这里会阻塞后续代码执行
int retvalue;
pthread_join(pthread, (void **) &retvalue);
if (retvalue != 0) {
LOGD("pthread_join ret=%d", retvalue);
}
LOGD("pthread_join end");
}
2. 函数参数传递
单个参数
单个参数直接传递到第四个参数即可。
pthread_create(&pthread, NULL, threadFunc, (void*) "this is params");
函数内接受参数
char* str = (char*) arg;
多个参数
多个参数可以通过结构体传递
struct thread_params {
std::string param1;
std::string param2;
};
void *threadFunc2(void *arg) {
thread_params *str;
str = (thread_params *) arg;
LOGD("execute native sub thread");
LOGD("params: %s", str->param1.c_str());
LOGD("params: %s", str->param2.c_str());
// 退出线程,返回结果,这里必须要执行,不然程序会报错
pthread_exit((void*)2);
return (void*)0;
}
extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThread(JNIEnv *env,
jclass clazz) {
pthread_t pthread;
thread_params *params = new thread_params;
params->param1 = "this is params1";
params->param2 = "this is params2";
jint ret = pthread_create(&pthread, NULL, threadFunc2, (void *) params);
LOGD("pthread_create ret=%d", ret);
}
3. 回调到java层
分四步
-
定义Java接口类
-
根据java的obj获取jclass。jclass可以理解为java中的class对象。
-
根据第二步中的jclass和方法名字和方法的签名获取该方法的jmethodID。
-
env调用java实例的方法。
定义Java接口类
// java回调接口 INativeListener.java
public interface INativeListener {
void onNativeCall(String value);
}
public native void nativeThreadCallBack(INativeListener callBack);
非子线程回调到java方法
extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThreadCallback(JNIEnv *env,
jclass clazz, jobject call_back) {
// 获取java中的对象
jclass cls = env->GetObjectClass(call_back);
// 获取回调方法的id
jmethodID mid = env->GetMethodID(cls, "onNativeCall", "()V");
// 调用java中的方法
env->CallVoidMethod(call_back, mid);
}
子线程回调到java方法
主要方法是JavaVM中的AttachCurrentThread和DetachCurrentThread两个方法。
JNI接口指针(JNIEnv)仅在当前线程中有效。如果另一个线程需要访问jvm,它必须首先调用AttachCurrentThread()将自己附加到 JVM并获取JNI接口指针。本机线程在调用DetachCurrentThread()来分离它自己之前一直连接到VM。
调用JavaVM中的AttachCurrentThread和DetachCurrentThread我们需要拿到JavaVM *vm指针。通过**jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)**方法全局变量保存一下vm即可。
JavaVM *gvm;
jobject gCallBackObj;
jmethodID gCallBackMid;
void *threadFunc3(void *arg) {
thread_params *str;
str = (thread_params *) arg;
LOGD("execute native sub thread");
LOGD("params: %s", str->param1.c_str());
LOGD("params: %s", str->param2.c_str());
JNIEnv *env = nullptr;
// 将当前线程添加到Java虚拟机上,返回一个属于当前线程的JNIEnv指针env
if (gvm->AttachCurrentThread(&env, nullptr) == 0) {
jstring jstr = env->NewStringUTF("write success");
// 回调到java层
env->CallVoidMethod(gCallBackObj, gCallBackMid, jstr);
// 删除jni中全局引用
env->DeleteGlobalRef(gCallBackObj);
// 从Java虚拟机上分离当前线程
gvm->DetachCurrentThread();
}
// 退出线程,返回结果,这里必须要执行,不然程序会报错
pthread_exit((void *) 2);
return (void *) 0;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
gvm = vm;
JNIEnv *env;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThreadCallback(JNIEnv *env,
jclass clazz, jobject call_back) {
gCallBackObj = env->NewGlobalRef(call_back);
jclass cls = env->GetObjectClass(call_back);
gCallBackMid = env->GetMethodID(cls, "onNativeCall", "(Ljava/lang/String;)V");
pthread_t pthread;
thread_params *params = new thread_params;
params->param1 = "this is params1";
params->param2 = "this is params2";
jint ret = pthread_create(&pthread, NULL, threadFunc3, (void *) params);
LOGD("pthread_create ret=%d", ret);
// 等待线程方法执行完成返回结果,注意这里会阻塞后续代码执行
int retvalue;
pthread_join(pthread, (void **) &retvalue);
if (retvalue != 0) {
LOGD("pthread_join ret=%d", retvalue);
}
LOGD("pthread_join end");
}