天天看点

Android下的JNI创建多线程的方法java的代码:jni中的代码:Android.mk文件中的代码:如何给线程函数传递多个参数:如何多线程同步通信:

本文参考了 http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html

这篇博文,加了点自己的东西

废话不多说,贴代码上来

java的代码:

package com.example.jni_thread_demo;
 
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
 
public class JNI_ThreadActivity extends Activity {
    private Button mButton = null;
    
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jni__thread);
        
        mButton = (Button)findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // 调用JNI中的函数来启动JNI中的线程
                mainThread();
            }
        });
        
        // 初始化JNI环境
        setJNIEnv();
        
    }
    
    //由JNI中的线程回调类方法
    private static void fromJNI(int i)
    {
        Log.v("Java---------->", ""+i);
    }
       //自己定义的线程回调成员方法
    private void From_JNI_Again (int i)
    {
        Log.v("Java_object------------>", ""+i);
    }
    
    // 本地方法
    private native void mainThread();
    private native void setJNIEnv();
    
    static
    {
        System.loadLibrary("JNIThread");
        
    }
}      

jni中的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<assert.h>
 
#include<jni.h>
#include<android/log.h>
 
 
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "jni_thread", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "jni_thread", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "jni_thread", __VA_ARGS__))
 
// 线程数
#define NUMTHREADS 5
// 指定要注册的类
 
#define JNIREG_CLASS "com/example/jni_thread_demo/JNI_ThreadActivity"
// 全局变量
JavaVM* g_jvm = NULL;
jobject g_obj = NULL;
 
void* thread_fun(void* arg)
{
    JNIEnv *env;
    jclass cls;
    jmethodID mid, mid1;
 
    // Attach主线程
    if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK)
    {
        LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
        return NULL;
    }
 
    // 找到对应的类
    cls = (*env)->GetObjectClass(env, g_obj);
 
    if(cls == NULL)
    {
        LOGE("FindClass() Error ......");
        goto error;
    }
    // 再获得类中的方法
    mid = (*env)->GetStaticMethodID(env, cls, "fromJNI", "(I)V");
    if(mid == NULL)
    {
        LOGE("GetStaticMethodID() Error ......");
        goto error;
    }
    // 最后调用java中的静态方法
    (*env)->CallStaticVoidMethod(env, cls, mid, (int)arg);
 
    //获得类中的“成员”方法
    mid1 = (*env)->GetMethodID(env, cls, "From_JNI_Again", "(I)V");
    if(mid == NULL)
    {
        LOGE("GetMethodID() Error ......");
        goto error;
    }
    // 最后调用类中“成员”方法
    (*env)->CallVoidMethod(env, g_obj, mid1, (int)arg);
 
    //错误处理代码
    error:
    //Detach主线程
    if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)
    {
        LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
    }
 
    pthread_exit(0);
}
 
/*
 * Class:     com_example_jni_thread_demo_JNI_ThreadActivity
 * Method:    mainThread
 * Signature: ()V
 */
/*不用JNI_OnLoad时的复杂命名方式
JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_mainThread
  (JNIEnv *env, jobject obj)
{
    int i;
    pthread_t pt[NUMTHREADS];
    for(i=0; i<NUMTHREADS; i++)
    {
        // 创建线程,并指明调用的函数
        pthread_create(&pt[i], NULL, &thread_fun, (void*)i);
    }
}*/
 
/*
 * Class:     com_example_jni_thread_demo_JNI_ThreadActivity
 * Method:    setJNIEnv
 * Signature: ()V
 *//*不用JNI_OnLoad时的复杂命名方式
JNIEXPORT void JNICALL Java_com_example_jni_1thread_1demo_JNI_1ThreadActivity_setJNIEnv
  (JNIEnv *env, jobject obj)
{
    // 保存全局JVM以便在子线程中使用
    (*env)->GetJavaVM(env, &g_jvm);
    // 不能直接赋值(g_obj = ojb)
    g_obj = (*env)->NewGlobalRef(env, obj);
}*/
 
JNIEXPORT void JNICALL native_mainThread(JNIEnv *env, /*jclass clazz*/ jobject obj)// 使用jclass和jobject都可以
{
    LOGI("native_mainThread");
    int i;
    pthread_t pt[NUMTHREADS];
 
    for(i=0; i<NUMTHREADS; i++)
    {
        // 创建线程,并指明调用的函数,注意只接收一个参数i作为thread_fun的参数,后面会介绍怎么传多个参数
        pthread_create(&pt[i], NULL, &thread_fun, (void*)i);
    }
}
 
JNIEXPORT void JNICALL native_setJNIEnv(JNIEnv *env, /*jclass obj*/ jobject obj)// 使用jclass和jobject都可以
{
    LOGI("native_setJNIEnv");
    // 保存全局JVM以便在子线程中使用
    (*env)->GetJavaVM(env, &g_jvm);
    // 不能直接赋值(g_obj = ojb)
    g_obj = (*env)->NewGlobalRef(env, obj);
}
 
/**
* Table of methods associated with a single class.
*/
static JNINativeMethod gMethods[] =
{
        {"mainThread", "()V", (void*)native_mainThread },   // 绑定:注意千万签名结尾不能加分号!!!!!!
        {"setJNIEnv", "()V", (void*)native_setJNIEnv },
};
 
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL)
    {
        return JNI_FALSE;
    }
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
    {
        return JNI_FALSE;
    }
 
    return JNI_TRUE;
}
 
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
            sizeof(gMethods) / sizeof(gMethods[0])))
    return JNI_FALSE;
 
    return JNI_TRUE;
}
 
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;
 
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("GetEnv failed!");
        return -1;
    }
    //===========================================
    assert(env != NULL);
 
    if (!registerNatives(env))
    {// 注册本地方法
        return -1;
    }
    //===========================================
    /* success -- return valid version number */
    result = JNI_VERSION_1_4;
 
    return result;
}      

Android.mk文件中的代码:

LOCAL_PATH :=$(call my-dir)
 
include $(CLEAR_VAR)
 
LOCAL_MODULE := JNIThread
LOCAL_SRC_FILES := JNI_Thread.c
LOCAL_MODULE_FILENAME := libJNIThread//如果报LOCAL_MODULE_FILENAME的错的话,需要加上这句话
LOCAL_LDLIBS := -llog
 
include $(BUILD_SHARED_LIBRARY)      

如何给线程函数传递多个参数:

涉及多参数传递给线程的,都需要使用结构体将参数封装后,将结构体指针传给线程

定义一个结构体

struct mypara
{
  var para1;//参数1
  var para2;//参数2
}      

将这个结构体指针,作为void *形参的实际参数传递 

struct mypara pstru;
pthread_create(&ntid, NULL, thr_fn,& (pstru));      

函数中需要定义一个mypara类型的结构指针来引用这个参数

void *thr_fn(void *arg)
{
  mypara *pstru;
  pstru = (* struct mypara) arg;
  pstru->para1;//参数1
  pstru->para2;//参数2    
}      

如何多线程同步通信:

至于多个线程是怎么进行同步通信的,可以参考这篇博文

http://blog.csdn.net/chenghongyue/article/details/8124976

继续阅读