JAVA学习(13) JAVA/C++互相调用 以及多线程

C++调用JAVA是JAVA的反射原理。
package com.ui.test;


import javax.swing.*;

public class test {
 private  JFrame mframe;
 private   JButton  btn;
 private   JPanel  panel;
 private    JLabel  label;
    public test() {
       mframe = new JFrame();
        mframe.setTitle("Hello");
        mframe.setSize(300, 300);

        panel = new JPanel();
        panel.setSize(100, 100);
        btn  = new JButton("按钮");
        btn.setSize(100, 100);
        panel.add(btn);
        label = new  JLabel("hello");
        panel.add(label);
        mframe.getContentPane().add(panel);
        mframe.setVisible(true);
        mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }
      static {
            System.loadLibrary("jnitest");
        }

        public native String testfuc(String instring);
        void Settxt(String txt)
        {
            label.setText(txt);
        }

    public static void main(String[] srgs)
    {
        test testx = new test();
         testx.testfuc("hello");
    }

}

#include <jni.h>

void  log(char*  TAG)
{
    char buf[256] = { 0 };
    sprintf(buf, "%s:thread id %d", TAG,::GetCurrentThreadId());
    OutputDebugStringA(buf);
}
JavaVM*  javavm;
JNIEnv * envm;
jobject obj;
int x = 0;
char buf[25];
DWORD  __stdcall  th2(void* lp)
{
    log("th2 begin");
    JNIEnv*  env;
    javavm->AttachCurrentThread((void**)(&env), NULL);
    log("th2 end"); 
    while (true)
    {
        sprintf(buf, "%d", x * 10);
        jstring rtstr2 = env->NewStringUTF(buf);
        env->GetObjectClass(obj);
        jclass cl = env->GetObjectClass(obj);
        jmethodID  id = env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
        env->CallVoidMethod(obj, id, rtstr2);
        x++;
        Sleep(1000);
    }
    return 0;
}
DWORD  __stdcall  th(void* lp)
{
    ::CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(th2), NULL, 0, 0);
    log("th1 begin");
    JNIEnv*  env;
    javavm->AttachCurrentThread((void**)(&env), NULL);

    log("th1 end");
    while (true)
    {
        sprintf(buf, "%d", x * 10);
        jstring rtstr2 = env->NewStringUTF(buf);
        env->GetObjectClass(obj);
        jclass cl = env->GetObjectClass(obj);
        jmethodID  id = env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
        env->CallVoidMethod(obj, id, rtstr2);
        x++;
        Sleep(1000);
    }

    return 0;
}
static jstring JNICALL Test(JNIEnv *env, jobject arg, jstring instring)
{
    envm = env; 
    const char *str = (const char *)env->GetStringUTFChars(instring, JNI_FALSE); 
    env->ReleaseStringUTFChars(instring, str);
    x++;
    sprintf(buf, "%d", x);
    jstring rtstr = env->NewStringUTF(buf);
    sprintf(buf, "%d", x*10);
    jstring rtstr2 = env->NewStringUTF(buf);



    jclass cl = env->GetObjectClass(arg);
    jmethodID  id= env->GetMethodID(cl, "Settxt", "(Ljava/lang/String;)V");
    env->CallVoidMethod(arg, id, rtstr2);
    obj= env->NewGlobalRef(arg);
    ::CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(th), NULL, 0, 0);
    return rtstr;
}
static const JNINativeMethod gMethods[] = { //定义批量注册的数组,是注册的关键部分
    { "testfuc", "(Ljava/lang/String;)Ljava/lang/String;", (void*)Test } // func2是在java中声明的native函数名,"()V"是函数的签名,可以通过javah获取。
};
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved) //这是JNI_OnLoad的声明,必须按照这样的方式声明
{
    javavm = vm;

    JNIEnv* env = NULL; //注册时在JNIEnv中实现的,所以必须首先获取它
    jint result = -1;

    if (vm->GetEnv(  (void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本
        return -1;


    jclass clazz;
    static const char* const kClassName = "com/ui/test/test";

    clazz =env->FindClass(kClassName); //这里可以找到要注册的类,前提是这个类已经加载到java虚拟机中。 这里说明,动态库和有native方法的类之间,没有任何对应关系。

    if (clazz == NULL)
    {
        ::MessageBoxA(0, "JNI_OnLoad", kClassName, 0);
        return -1;
    }


    if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) //这里就是关键了,把本地函数和一个java类方法关联起来。不管之前是否关联过,一律把之前的替换掉!
    {
        printf("register native method failed!\n");
        return -1;
    }

    return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}
  1. JNI_OnLoad 保存JavaVM指针
  2. 在JAVA调用在JAVA调用C++时,保存JAVA对象,obj= env->NewGlobalRef(arg)使得对象可以全局共享
  3. 多线程中使用javavm->AttachCurrentThread 附加线程到Java线程中
  4. 附加线程后,使用env->GetObjectClass(obj) 获取对象的class
  5. AttachCurrentThread 不会立刻修改线程id,不知什么原理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
目录 I. 目录 1 II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的DLL文件(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java文件 7 2、 生成.h头文件 8 3、 用c/cpp实现这个头文件 9 三 测试 10 四 最后补充 11 III. java c/cpp互相调用实例(姊妹篇之二)——c/cpp调用java 11 一、 编写java代码 12 二、 编译java代码 12 三、 编写 C/C++ 代码 13 四、 运行exe 18 IV. Java JNI 编程进阶 18 一、 解决性能问题 18 二、 解决本机平台接口调用问题 19 三、 嵌入式开发应用(JNI小例子) 20 1、 新增一个基础类 22 2、 定义新类继承基础类 23 3、 编写调用类 23 4、 新增两个本地方法 24 5、 修改 RunMain 类 25 6、 新增一个方法处理java对象 26 7、 新增一个方法处理数组 29 8、 改写RunMain 32 四、 参考资料: 33 V. Eclipse+CDT+MinGW 进行JAVA调用C/C++ 34 一、 安装eclipse3.2。 34 二、 安装MinGW。 34 1、 下载MinGW 34 2、 安装 34 3、 安装版本 34 4、 选择安装的编译器 34 5、 选择安装路径,下一步 35 6、 等待下载软件 35 三、 MinGW的环境变量设置 35 1、 设置Path 35 2、 设置C_INCLUDE_PATH 35 3、 设置CPLUS_INCLUDE_PATH 35 四、 做一个小技巧修改 35 五、 安装CDT插件 36 1、 下载CDT插件 36 2、 安装CDT插件 36 六、 简单介绍CDT的使用吧 36 1、 新建一个C++项目 36 2、 输入New Project名字 36 3、 给项目新建一个的源文件 36 4、 接着出现文件添加的窗口,在File Name栏里面写上文件名 36 5、 编辑hello.cpp 37 6、 添加一个编译命令 37 七、 让我们开始进入真正的工作吧! 38 The Java side 38 1、 建立Java工程JavaHello,编写java类 38 2、 用命令生成头文件 38 The C side-Compiling the Library 40 1、 建立标准C工程Cpro,并生成dll文件 40 1) 将生成的头文件test_Hello.h拷贝到C工程Cpro下 40 2) 编写C类Hello.c,内容为: 40 3) 在C工程Cpro下建立hello.def文件(用于定义导出的函数),内容为: 40 4) 在C工程Cpro下建立makefile文件,内容为: 40 5) Make Targets 40 6) Make Targets视图下双击step1,在C工程Cpro下生成hello.o 文件。 41 7) Make Targets视图下双击step1,在C工程Cpro下生成hello.dll 文件。 41 2、 JAVA调用DLL 41 1) 将hello.dll拷贝到Java工程JavaHello下。 41 2) 运行Hello.java,则可以看到输出结果: 41 1) 将Hello.c改为Hello.cpp 41 2) 将makefile内容改为: 41 3) 其他的几乎都不用改变也可以。 42 评论: 42 VI. c++如何调用java程序 51 DemoMain.java内容如: 51 采用vc6++ IDE,采用JNI技术实现。 51 1、 编译时 51 2、 运行时 51 程序的关键在 53 VII. JNI 53 一、 定义 53 二、 设计目的 54 三、 书写步骤 54 1) 编写java程序:这里以HelloWorld为例。 54 2) 编译 55 3) 生成扩展名为h的头文件 55 4) 编写本地方法实现和由javah命令生成的头文件里面声明的方法名相同的方法。 56 5) 生成动态库 56 6) 运行程序 java HelloWorld就ok. 56 四、 调用中考虑的问题 56 1) java和c是如何互通的? 57 2) 如何将java传入的String参数转换为c的char*,然后使用? 57 3) 将c中获取的一个char*的buffer传递给java? 57 4) 不知道占用多少空间的buffer,如何传递出去呢? 58 五、 对JAVA传入数据的处理 58 1) 如果传入的是bytearray的话,作如下处理得到buffer: 58 VIII. C/C++调用JAVA类 58 一、 加载虚拟机: 59 二、 获取指定对象的类定义: 59 三、 获取要调用的方法: 59 四、 调用JAVA类方法: 60 五、 获得类属性的定义: 60 六、 数组处理: 60 七、 异常: 60 八、 多线程调用 61 Java代码 61 命令行运行:javap -s -p MyTest ,输出: 62 C代码testjava.c: 62 编译: 65 运行结果: 65
Java多线程可以调用DLL(Dynamic-Link Library)来进行一些特定操作。 首先,在Java调用DLL需要使用到Java Native Interface(JNI)技术。JNIJava提供的一种机制,用于在Java程序中调用本地的C/C++代码。通过JNI,我们可以在Java程序中加载和调用DLL中的函数。 在多线程调用DLL的过程如下: 1. 首先,在Java中编写一个JNI的接口类,用于定义与DLL中函数的映射关系。这个接口类需要使用Java的native关键字来声明与DLL中函数对应的本地方法。 2. 在DLL中实现与接口类中声明的本地方法对应的C/C++函数。这些函数可以通过DLL导出符号的方式供Java程序调用。 3. 在Java程序中加载DLL并调用其中的函数。 使用多线程调用DLL时,需要注意以下几点: 1. 线程安全性:在多线程环境下调用DLL时,需要确保DLL中的函数是线程安全的,即能够正确处理多个线程间的共享数据。 2. 同步控制:如果DLL中的函数需要访问共享资源,需要在Java程序中使用同步控制机制,如synchronized关键字或Lock对象来确保线程之间的互斥访问。 3. 线程间通信:如果多个线程需要相互通信,可以通过共享内存或消息传递的方式实现。在DLL中可以使用线程同步的机制来实现线程间的互斥、等待和通知操作。 总之,Java多线程可以通过JNI技术调用DLL来完成一些底层的特定操作。在进行多线程调用DLL时,需要保证线程安全性,确保合适的同步控制和线程间通信方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值