精华内容
下载资源
问答
  • 在主线程中可以findclass,但是在子线程中却找不到,找的是同一个class,在子线程正可以找到系统的类,比如java/long/String
  • 我能够运行类似的代码(如下所示),其中有线程访问同一JVM(macOS).我正在使用pthread.很少有重要的事情>将线程附加到JVM(根据文档,一次只能有一个线程可以使用JVM)>连接螺纹>我想也最好使用互斥体以防止...

    我能够运行类似的代码(如下所示),其中有多个线程访问同一JVM(macOS).我正在使用pthread.

    很少有重要的事情

    >将线程附加到JVM(根据文档,一次只能有一个线程可以使用JVM)

    >连接螺纹

    >我想也最好使用互斥体以防止连接多个线程

    main.c

    #include

    #include

    #include

    #define NUM_THREADS 6

    pthread_mutex_t mutexjvm;

    pthread_t threads[NUM_THREADS];

    struct JVM {

    JNIEnv *env;

    JavaVM *jvm;

    };

    void invoke_class(JNIEnv* env);

    void *jvmThreads(void* myJvm) {

    struct JVM *myJvmPtr = (struct JVM*) myJvm;

    JavaVM *jvmPtr = myJvmPtr -> jvm;

    JNIEnv *env = myJvmPtr -> env;

    pthread_mutex_lock (&mutexjvm);

    printf("I will call JVM

    ");

    (*jvmPtr)->AttachCurrentThread(jvmPtr, (void**) &(env), NULL);

    invoke_class( env );

    (*jvmPtr)->DetachCurrentThread(jvmPtr);

    pthread_mutex_unlock (&mutexjvm);

    pthread_exit(NULL);

    }

    JNIEnv* create_vm(struct JVM *jvm)

    {

    JNIEnv* env;

    JavaVMInitArgs vm_args;

    JavaVMOption options;

    options.optionString = "-Djava.class.path=./";

    vm_args.options = &options;

    vm_args.ignoreUnrecognized = 0;

    vm_args.version = JNI_VERSION_1_6;

    vm_args.nOptions = 1;

    int status = JNI_CreateJavaVM(&jvm->jvm, (void**)&env, &vm_args);

    if (status < 0 || !env)

    printf("Error

    ");

    return env;

    }

    void invoke_class(JNIEnv* env)

    {

    jclass Main_class;

    jmethodID fun_id;

    Main_class = (*env)->FindClass(env, "Main");

    fun_id = (*env)->GetStaticMethodID(env, Main_class, "fun", "()I");

    (*env)->CallStaticIntMethod(env, Main_class, fun_id);

    }

    int main(int argc, char **argv)

    {

    struct JVM myJvm;

    myJvm.env = create_vm(&myJvm);

    if(myJvm.env == NULL)

    return 1;

    pthread_mutex_init(&mutexjvm, NULL);

    for(int i=0; i

    pthread_create(&threads[i], NULL, jvmThreads, (void*) &myJvm);

    pthread_join(threads[i], 0);

    }

    (*myJvm.jvm)->DestroyJavaVM(myJvm.jvm);

    }

    Main.java

    public class Main {

    public static void main(String[] args){

    System.out.println("Hello, world");

    }

    public static int fun() {

    System.out.println("From JVM");

    return 0;

    }

    }

    生成文件

    all: Main.class main

    Main.class: Main.java

    javac Main.java

    main.o: main.c

    llvm-gcc -c main.c \n -I${JAVA_HOME}/include \n -I${JAVA_HOME}/include/darwin/ \n

    main: main.o

    ld -o main -L${JAVA_HOME}/jre/lib/server/ \n -ljvm \n -rpath ${JAVA_HOME}/jre/lib/server \n -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk \n -demangle -dynamic -arch x86_64 \n -macosx_version_min 10.12.0 \n -lSystem \n -rpath ${JAVA_HOME}/jre/lib/server/ \n main.o

    clean:

    rm -f Main.class main main.o

    运行代码后,将得到以下结果:

    ./main

    I will call JVM

    From JVM

    I will call JVM

    From JVM

    I will call JVM

    From JVM

    I will call JVM

    From JVM

    I will call JVM

    From JVM

    I will call JVM

    From JVM

    展开全文
  • jni中用多线程调用java代码

    热门讨论 2013-07-17 20:59:27
    本项目主要是实现了在jni中用多线程调用java对象。代码调试通过。直接导入到eclipse即可运行
  • 一个Java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回,同时把JNI接口的指针JNIEnv *env(虚拟机环境指针),和jobject obj保存在DLL中的变量里.一段时间后,DLL中的消息接收线程...
    
    

    一个Java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回,同时把JNI接口的指针JNIEnv *env(虚拟机环境指针),和jobject obj保存在DLL中的变量里.一段时间后,DLL中的消息接收线程接收到服务器发来的消息,并试图通过保存过的env和obj来调用先前的java对象的方法(相当于JAVA回调方法)来处理此消息此时程序会突然退出(崩溃).

    即前台JAVA线程发送消息,后台线程处理消息,归属于两个不同的线程,不能使用相同的JNIEnv变量,这里可以利用一个机制: 利用全局的 JavaVM * 指针得到当前线程的 JNIEnv* 指针,与在C++中两个线程使用TLS进行局部存储类似的原理。


    具体方法:

    获取全局的JavaVM变量:

    /* Our VM */
    JavaVM *g_vm;

    env->GetJavaVM(&g_vm); //来获取JavaVM指针.获取了这个指针后,将该JavaVM保存起来。


    线程 JNIEnv 指针,线程中获取 JNIEnv 方法:

       JNIEnv *e;
       JavaVMAttachArgs thread_args;

     thread_args.name = "NFC Message Loop";
       thread_args.version = nat->env_version;
       thread_args.group = NULL;

       g_vm->AttachCurrentThread(&e, &thread_args); //后面的参数可以传空

    while(1){

    //...

    g_vm->DetachCurrentThread(); //使用完成后


    经过如此以后,JNIEnv 就可以由每个线程独自使用了。


    而如果我们需要回调JAVA方法,jobject 也不能在多个线程中共享,如此可以在多个线程中使用了:

    gs_object=env->NewGlobalRef(obj);//创建一个全局变量

    将传入的obj(局部变量)保存到gs_object,从而其他线程可以使用这个gs_object(全局变量)来操纵这个java对象了

    完整示例代码如下:

    java代码:Test.java:

    [java] view plain copy
     print?
    1. import java.io.*;    
    2. class Test implements Runnable    
    3. {    
    4.  public int value  = 0;    
    5.  static{ System.loadLibrary("Test");}    
    6.     
    7.  public native void setEnev();//本地方法     
    8.     
    9. public static void main(String args[]) throws Exception    
    10.  {    
    11.    Test t = new Test();    
    12. <span style="color:#FF0000;">   t.setEnev(); //调用本地方法   </span>  
    13.     
    14.     while(true)    
    15.     {     
    16.       Thread.sleep(1000);    
    17.       System.out.println(t.value);    
    18.     }    
    19.   }    
    20. }  


    JNI代码 Test.cpp:

    static JavaVM *gs_jvm=NULL;  
    static jobject gs_object=NULL;  
    static int gs_i=10;  
      
    JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj)  
    {  
        env->GetJavaVM(&gs_jvm); //保存到全局变量中JVM   
        //直接赋值obj到DLL中的全局变量是不行的,应该调用以下函数:   
        gs_object=env->NewGlobalRef(obj);  
      
     HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFun,0,NULL,NULL);  
    }


    void WINAPI ThreadFun(PVOID argv)//JNI中线程回调这个方法   
    {   
     JNIEnv *env;  
     gs_jvm->AttachCurrentThread((void **)&env, NULL);  
     jclass cls = env->GetObjectClass(gs_object);   //获取JAVA线程中的全局对象
     jfieldID fieldPtr = env->GetFieldID(cls,"value","I");   // 获取JAVA对象

      
     while(1)  
     {  
        Sleep(100);  
       //这里改变JAVA对象的属性值(回调JAVA)   
       env->SetIntField(gs_object,fieldPtr,(jint)gs_i++);  
      }  
    }


    对于如上的思路,只要你理解了TLS的用法就很容易理解以上内容了。

    附加介绍 TLS (thread-local storage) 一下,网上摘抄的内容:

    线程是执行的单元,同一个进程内的多个线程共享了进程的地址空间,线程一般有自己的栈,但是如果想要实现某个全局变量在不同的线程之间取不同的值,而且不受影响。一种办法是采用线程的同步机制,如对这个变量的读写之处加临界区或者互斥量,但是这是以牺牲效率为代价的,能不能不加锁呢?线程局部存储就是干这个的。

    Windows中是根据线程局部存储索引来标识的(这个标识的分配和释放由TlsAlloc和TlsFree完成),有了个这个”标识“就可以在各个线程中调用TlsGetValue或者TlsSetValue读取或者设置各线程各自的值;

    DWORD TlsAlloc(void);  

    BOOL TlsFree(DWORD dwTlsIndex); 
    LPVOID TlsGetValue(DWORD dwTlsIndex); 
    BOOL TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue); 


    linux 平台对应的接口函数:

    int pthread_key_create(pthread_key_t * key, void (*)(void *)); 
    int pthread_key_delete(pthread_key_t); 
    void *pthread_getspecific(pthread_key_t); 
    int pthread_setspecific(pthread_key_t, const void *);

    展开全文
  • JNI定义如下 [code="java"]package jni; public class Test { public native void addOne(); public native int getGlobalValue(); } [/code] JNI对应的C代码 [code="C"]#...
    JNI定义如下
    package jni;   
    public class Test {
    public native void addOne();
    public native int getGlobalValue();
    }


    JNI对应的C代码
    #include"jni_Test.h"   
    #include <stdio.h>
    int value = 1000;
    JNIEXPORT void JNICALL Java_jni_Test_addOne(JNIEnv *env, jobject obj)
    {
    value = value +1;
    }
    JNIEXPORT jint JNICALL Java_jni_Test_getGlobalValue(JNIEnv *env, jobject obj)
    {
    return value;
    }


    创建多个线程操作全局变量
    package jni;
    public class MainCygwin {
    static{
    System.loadLibrary("test");
    }
    public static void main(String[] args) {
    Test hl = new Test();
    Thread t1 = new Thread(new Add("first",hl));
    Thread t2 = new Thread(new Add("second",hl));
    t1.start();
    t2.start();
    }
    }
    class Addimplements Runnable{
    private String name;
    private Test hl;
    public Add(String name,Test hl)
    {
    this.name = name;
    this.hl = hl;
    }
    @Override
    public void run() {
    int i = 0;
    while(i < 100)
    {
    i++;
    h1.addOne();
    System.out.println(this.name + hl.getGlobalValue());
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }


    [color=red]两个加操作线程操作的是同一个value变量[/color]
    展开全文
  • android JNI 多线程调用与回调

    千次阅读 2013-05-16 15:39:36
    说明: JNI调用比较简单,根据JNI给出的实例,本内容主要讲多线程使用回调步骤: 1. 编写说明,调用JNI类。两种方法:  1)通过包+类名找到  static jclass jNativesCls;  #define CB_CLASS "org/...

    说明: JNI调用比较简单,根据JNI给出的实例,本内容主要讲多线程使用回调步骤:

    1.  编写说明,调用JNI类。两种方法:

       1)通过包+类名找到

             static jclass jNativesCls;

             #define CB_CLASS "org/piaozhiye/study/Natives"

             jNativesCls = (*env)->FindClass(env,CB_CLASS);

        2) 通过 JNIEXPORT jint JNICALL Java_org_piaozhiye_study_Natives_LibMain
      (JNIEnv * env, jclass class);取得其中的class。 唯一区别就是要求调用的函数与回调函数在相同类中


    2. 编写回调函数  ,如果不太懂得写,可以写个接口,然后用javah 生成,再抄写

           #define CB_CLASS_MSG_CB "OnMessage"    // 函数名
          #define CB_CLASS_MSG_SIG "(Ljava/lang/String;I)V"   //参数与返回值

         jmethodID  mSendStr = (*env)->GetStaticMethodID(env,jNativesCls,CB_CLASS_MSG_CB,CB_CLASS_MSG_SIG);  // 取得方法ID

         注意: 在使用时,每次调用时需要加上这句

                   (*g_VM)->AttachCurrentThread(g_VM,&env,NULL);   //附加到当前线程中, 生成 env

                  (*env)->CallStaticVoidMethod(env,jNativesCls,mSendStr,(*env)->NewStringUTF(env,text),(jint)level); //再进行使用,若不同线程,env则不相同,造成调用出错


    3. 碰到的报错:

        1) JNI ERROR (app bug): accessed stale local reference 0x50100019  不同线程回调时报的错,这错误排查一整天,终于找到了,是由于Mamifest.xml 配置问题造成的,把uses-sdk配置改成这样: <uses-sdk android:minSdkVersion="7" />

    展开全文
  • JNI native多线程调用Java静态方法

    千次阅读 2016-09-13 12:25:18
    1.因为env不能多线程共享,而JavaVM可以,所以要通过在JNI入口c文件下把JavaVM保存起来,提供给其他线程使用,然后就可以在其他线程中通过JavaVM来拿到env;同时我也将java类设置为全局变量,供给其
  • 1.引入头文件 (注:不用添加 pthread.h 头文件) 2. 贴上 C++ 代码 ... 会报红,不必理会//当动态库被加载时这个函数被系统调用 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
  •  最近公司项目用到C/C++的... JAVA的业务需要在调用过程中采用多线程的方式,因为C实现算法中用到了很多全局静态变量,JNI调用的时候就不可避免的出现各个线程间的全局变量互相干扰的问题。然后各种查找解决方...
  • JNI里的多线程 在本地方法里写有关多线程的代码时,需要知道下面几个约束: 一个JNIEnv指针只在与它关联的线程里有效,也就是说,在线程间传递JNIEnv指针和在多线程环境里通过缓存来使用它是不允许和不安全的。JVM...
  • 一、jni调用java对象JNI提供的功能之一是在本地代码中使用Java对象。包括:创建一个java类对象和通过函数传递一个java对象。创建一个java类对象,首先需要得到得到使用FindClass/GetObjectClass函数得到该类,然后...
  • 修改文如下:问题描述:一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回,同时把JNI接口的指针JNIEnv *env(虚拟机环境指针),和jobject obj保存在DLL中的变量里.一段时间后,...
  • 当程序多线程调用打开输入流的时候,就弹出 [img=https://img-bbs.csdn.net/upload/201801/04/1515048926_906588.png][/img] 这个错误。 当然偶尔程序还是可以跑通的,就很奇怪,下面是程序 AVFormatContext *...
  • [JNI] java 多线程调用native 方法

    千次阅读 2013-09-30 16:38:54
    http://hi.baidu.com/zzcqh/item/25709e49ddb348afdf2a9f11 http://blog.csdn.net/fanbird2008/article/details/6399630 http://blog.csdn.net/jinlking/article/details/5319750 http://hllvm.group.iteye.com/g
  • 一、jni调用java对象 JNI提供的功能之一是在本地代码中使用Java对象。包括:创建一个java类对象和通过函数传递一个java对象。创建一个java类对象,首先需要得到得到使用FindClass/GetObjectClass函数得到该类,然后...
  • jni调用c++代码时,若c++实现里面采用了多线程,则会出现jvm crash的情况。 查了一下jni的说明,其中提到:JNIEnv *env指针和jobject对象都不能跨线程使用,但是java虚拟机jvm可以共享 对于jobject,解决办法是 ...
  • 一、jni调用java对象   JNI提供的功能之一是在本地代码中使用Java对象。包括:创建一个java类对象和通过函数传递一个java对象。创建一个java类对象,首先需要得到得到使用FindClass/GetObjectClass函数得到该类,...
  • 1.JNI开发时经常需要使用到jstring和string的转换,还有C++多线程中使用JNIEnv,因此特意写了这个类,方便以后的开发使用。 注意: 如果要使用打印日志的LOGI和LOGE需要在mk文件中链接log库 LOCAL_LDLIBS := -llog ...
  • 多线程JNI开发踩坑

    2020-08-26 15:22:24
    JNI开发时,最重要的就是JNIEnv *env这个参数,它代表着Java本地接口环境(Java Native Interface Environment),通过它可以在native层中与java层进行交互。因此在每个定义的native方法中都有这个参数。 二、问题...
  • 如何在多线程中使用JNI

    千次阅读 2014-12-30 12:14:54
    如果你想了解JNI在如何在多线程下使用 如果你在子线程使用JNI时遇到findClass不能找到目标Class,而在主线程下却能找到该Class的问题。或是GetEnv返回NULL的问题 如果你想多学点编程技术的话 那么,这篇文章就是为...
  • JNI 多线程

    2014-03-03 15:20:00
    JNI编程和Linux上的C/C++编程还是挺相似的,每次java调用JNI中的函数时都会传入有关JVM的一些参数(如JNIEnv,jobject),每次JNI回调java中的方法时都要通过JVM的有关参数来实现,当在JNI中涉及到多线程的话还是有...
  • JNI多线程

    2012-11-14 11:17:32
     JNI编程和Linux上的C/C++编程还是挺相似的,每次java调用JNI中的函数时都会传入有关JVM的一些参数(如JNIEnv,jobject),每次JNI回调java中的方法时都要通过JVM的有关参数来实现,当在JNI中涉及到多线程的话还是...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 256
精华内容 102
关键字:

多线程调用jni