JNI:C++回调JAVA的函数

摘要

JNI, 对象全局引用NewGlobalRef(), 线程绑定JAVA虚拟机AttachCurrentThread()

测试代码

JAVA

MainApp

//MainApp.java
import sun.misc.*;


public class MainApp {
	static {
        System.loadLibrary("animal");
    }
 
    public static void main(String[] args) {
		TestSignal handler = new TestSignal();
        Signal.handle(new Signal("TERM"), handler);
        Signal.handle(new Signal("INT"), handler);
        //Signal.handle(new Signal("USR1"), handler);
        //Signal.handle(new Signal("USR2"), handler);

        Animal animal = new Animal("Puppy");  
        animal.printName();
		
		animal.setCallback();
		
		while(handler.is_running()) {
			System.out.println("I am Main Thread.");
			try {
				Thread.sleep(5000);
			}
			catch(InterruptedException e) {
				System.out.println("InterruptedException.");
				e.printStackTrace();
			}
		}
		
		animal.closeCallback();
    }  
}

Animal

Animal.java提供了回调函数void logMessage(String);

//Animal.java  
public class Animal {  
    public String name;  
    public Animal(String name) {  
        this.name = name;  
    }

    public void printName() {  
        System.out.println("Animal [" + name + "]");  
    }

    private void logMessage(String msg) {
        System.out.println("msg:" + msg);
    }
 
    public native void setCallback();
	public native void closeCallback();
	
	protected long mObj;
}

编译“javac Animal.java”执行后,要执行“javah -jni Animal”生成C++头文件Animal.h。

信号处理

//TestSignal.java

import sun.misc.*;

@SuppressWarnings("restriction")
public class TestSignal implements SignalHandler {
    public void handle(Signal arg0) {
        System.out.println(arg0.getName() + " is recevied.");
		if(arg0.getName() == "TERM") {
			brunning = false;
		}
    }
	
	public boolean is_running() {
		return brunning;
	}
	
	private boolean brunning = true;
}

JNI代码

头文件Animal.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class Animal */

#ifndef _Included_Animal
#define _Included_Animal
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Animal
 * Method:    setCallback
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Animal_setCallback
  (JNIEnv *, jobject);

/*
 * Class:     Animal
 * Method:    closeCallback
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Animal_closeCallback
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

源代码文件Animal.cpp

#include "Animal.h"

#include 
#include 
#include 
#include 
#include 


static JavaVM *g_VM = NULL;

class CLog {
public:
	CLog();
	~CLog();
	/*static CLog& instance() {
		return CLog::static_clog_;
	}*/
	
	bool attach(JavaVM* vm, JNIEnv *env, jobject thiz);
	bool detach(JNIEnv *env);
	
	void set_JavaVM(JavaVM* jVM) {
		javaVM_ = jVM;
	};
private:
	CLog(const CLog& obj);
	CLog& operator=(const CLog& obj);

	void attach_thread();
	void dettach_thread();
	
	static void *TestThread(void *arg);
private:
    bool brunning_ = true;
    JavaVM* javaVM_ = NULL;
    JNIEnv *env_ = NULL;
    jobject thiz_ = NULL;
	
	pthread_t tid_;
	
	//static CLog static_clog_;
};


//CLog CLog::static_clog_;

#define  CONSTRUCT(T) { T *t = new T(); \
    jclass clazz = (jclass)(*env).GetObjectClass(thiz); \
    jfieldID fid = (jfieldID)(*env).GetFieldID(clazz, "mObj", "J"); \
    jlong jstr = (jlong) (*env).GetLongField(thiz, fid);  \
    (*env).SetLongField(thiz, fid, (jlong)t);}
 
#define OBJECT(T,name) jclass clazz = (jclass)env->GetObjectClass(thiz); \
     jfieldID fid = env->GetFieldID(clazz, "mObj","J");  \
     T *name = (T *)env->GetLongField(thiz, fid);
 
#define DESTRUCT(T)  {jclass clazz = (jclass)env->GetObjectClass(thiz); \
     jfieldID fid = env->GetFieldID(clazz, "mObj","J");  \
     T *object = (T *)env->GetLongField(thiz, fid); \
     if(object != NULL) delete object; \
     (*env).SetLongField(thiz, fid, (jlong)0);}


CLog::CLog() {
}


CLog::~CLog() {
}


bool CLog::attach(JavaVM* vm, JNIEnv *env, jobject object) {
	javaVM_ = vm;
    thiz_ = env->NewGlobalRef(object);
	
	int ret = pthread_create(&tid_, NULL, CLog::TestThread, this);
	printf("create thread, ret = %d.\n", ret);
	
	return true;
}


bool CLog::detach(JNIEnv *env) {
    env->DeleteGlobalRef(thiz_);
    thiz_ = NULL;

	brunning_ = false;
	pthread_join(tid_, NULL);

	return false;
}


void CLog::attach_thread()
{
    if(javaVM_ == NULL) return;
    if(thiz_ == NULL) return ;
 
    int ret = javaVM_->AttachCurrentThread((void **)&env_, NULL);
    if(ret != 0)
    {
    }
}
 
void CLog::dettach_thread()
{
    if(javaVM_ == NULL)
		return;
     
	 javaVM_->DetachCurrentThread();
     env_ = NULL;
}


void *CLog::TestThread(void *arg) {
	CLog *pThis = (CLog *)arg;
	pThis->attach_thread();

    for(int i = 0; i < 100 && pThis->brunning_; ++i) {
		char buffer[64];
        sprintf(buffer, "%5d", i);
        jstring msg_ = pThis->env_->NewStringUTF(buffer);
        jclass clazz = pThis->env_->GetObjectClass(pThis->thiz_);
        jmethodID  jid = pThis->env_->GetMethodID(clazz, "logMessage",  "(Ljava/lang/String;)V");
        pThis->env_->CallVoidMethod(pThis->thiz_, jid, msg_);
        pThis->env_->DeleteLocalRef(msg_);
		
		sleep(5);
	}
	
	pThis->dettach_thread();

	return NULL;
}

/*
 * Class:     Animal
 * Method:    setCallback
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Animal_setCallback
  (JNIEnv *env, jobject thiz)
{
	CONSTRUCT(CLog);
    OBJECT(CLog,log);
    if(log == NULL) {
		return;
	}

	log->attach(g_VM, env, thiz);
}


/*
 * Class:     Animal
 * Method:    closeCallback
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Animal_closeCallback
  (JNIEnv *env, jobject thiz)
{
	{
        OBJECT(CLog, log);
        if (log == NULL) {
			return;
		}

        log->detach(env);
    }

    DESTRUCT(CLog);
}


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    //jint result = -1;
 
    if(JNI_OK != vm->GetEnv((void**) &env, JNI_VERSION_1_4)) {
		
        return -1;
    }

    assert(env != NULL);
	g_VM = vm;

    return JNI_VERSION_1_4;
}

编译

g++ -std=c++11 -shared -I/home/syq/java/jdk-14.0.2/include -I/home/syq/java/jdk-14.0.2/include/linux -fPIC Animal.cpp -o libanimal.so

运行

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
java MainApp

引用

  1. Java程序编译和运行的过程
  2. JNI c++对象与java对象互关联

你可能感兴趣的:(JAVA,c++,java,jni)