記事のディレクトリ
記事のシリーズ
1.基本動作JNIのJava層は、ネイティブメソッドを作成し、対応する関数を生成するJNI
JNIのJavaのプロパティ基本操作2.動作
するJavaのJNI 3基本操作方法
JNI 4ロードおよびアンロード機能、動的登録および抗の基本動作ローカル登録する方法
のプロセス(同期ブロックのJavaと同様に)マルチスレッドクリティカルセクションのJNI 5.基本的な動作を
序文
ネイティブコードでは、同様の達成するためにJavaのsynchronized
機能を。それは一つのスレッドのみが動作することができ、同時に、重要な領域です。
synchronized(obj) {
//这里就是临界区
}
:達成するための機能
、使用<pthread.h>
中pthread_create()
のスレッドを作成し、
使用「セマフォsemaphore.h」は、sem_wait()和sem_post()
ミューテックスが使用または「pthread.hの」;信号を待って送信するためにpthread_mutex_lock()和pthread_mutex_unlock()
達成します。
JNIも機能と同様の機能を提供しMonitorEnter(jobject)
、そしてMonitorExit(jobject)
。
jオブジェクトについて:
jni.h中で、知ることができ、JCLASS、JSTRING、jarray、すべての種類の名前が変更JOBJECT jthrowableです。
通常、マルチスレッドオペレーティング共有変数に、このような動作は、同期相互に排他的なの使用を必要とします。
例
ThreadTest.cppファイルで書かれています。(主にenv->
書かれた利便ああ^ _ ^)
#include <jni.h>
#include <pthread.h> //线程
#include <malloc.h>
#include <unistd.h>
#include <cstdlib> //c stdlib.h
#include <ctime> //c time.h
#include <cstdio> //c stdio.h
#include <android/log.h>
#ifndef LOG_TAG
#define LOG_TAG "stone.stone"
#define slogd(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#endif
struct Args3 {
JavaVM* vm;
int tid;
};
void* threadFun3(void* args); //线程函数;声明在前,方便test()使用。
void test(JavaVM *vm) {
pthread_t pid;
for(int i = 0; i < 10; i++) {
struct Args3 *args = (Args3 *)(malloc(sizeof(struct Args3)));
args->vm = vm;
args->tid = i;
//像如下这样传递,运行还是会报错的,是因为,指针变量的空间太小
// struct Args3 args3 = {vm, i};
// struct Args3* args = &args3;
pthread_create(&pid, nullptr, threadFun3, args);
}
}
static int count = 0;
void* threadFun3(void* arg) {
Args3* args = (struct Args3 *)arg;
JavaVM* vm = args->vm;
JNIEnv *env = nullptr;
int status = vm->GetEnv((void **)(&env), JNI_VERSION_1_6);
if (status < 0) {
slogd("stone->get env error. get 不到 env,就需要 attach");
status = vm->AttachCurrentThread(&env, nullptr);
if (status < 0) {
slogd("stone->AttachCurrentThread error");
return nullptr;
} else {
slogd("stone->AttachCurrentThread success");
}
}
env->MonitorEnter(g_ObjCall); //进入监视
int tid = args->tid;
time_t t = time(nullptr) + count;
srand(t);//设置随机因子,不同的随机因子,生成的随机数才不同
sleep(rand() % 3); //随机数 取模,再线程睡眠 0~2秒
count++;
slogd("stone->threadFun3. tid=%d, count=%d, time=%ld", tid, count, t);
env->MonitorExit(g_ObjCall); //退出监视
return nullptr;
}
別の主要なCPPファイルで:
#include "ThreadTest.cpp"
extern jobject g_ObjCall;//可以被其它地方使用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (JNI_OK != vm->GetEnv(reinterpret_cast<void**> (&env),JNI_VERSION_1_6)) {
slogd("JNI_OnLoad could not get JNI env");
return JNI_ERR;
}
//jclass clazz = env->FindClass("com/stone/ndk/jni/JniActivity");
//g_ObjCall = env->NewGlobalRef(env->AllocObject(clazz));
g_ObjCall = env->NewGlobalRef(env->NewIntArray(1));
test(vm);
return JNI_VERSION_1_6;
}
本実施形態では、ミューテックス効率的な動作では、その結果が出力され、ほとんどの場合、全体の実行時間よりも大きいが2秒であった。有効でない場合、すなわち、マルチスレッド並列動作、2秒以上の全体的な動作時間です。
問題が発生し、使用上の注意
- スレッド関数はつ以上のパラメータは、必要な構造を転送し、そして構造が動的メモリを必要とするポインタが渡されます。場合非動的オープンストレージスペースポインタ変数は不十分であり、崩壊します。
- 試験()VMのパラメータであり、書き換え
JNI_OnLoad(JavaVM* vm, void* reserved)
た場合に得られます - なぜスレッド関数に渡すために必要
JavaVM*
なパラメータ:
原因JniEnv*
ができないスレッドのシェアは、別のスレッドを取得する子が必要で、それは買収を通じてあるJavaVM*
の。
まずvm->GetEnv()
取得する権利場合、それはスレッドが子会社となっていることを意味し、
そうでない場合は、経由vm->AttachCurrentThread(&env, NULL)
子会社スレッド、ENVを取得します - なぜグローバル参照変数g_ObjCallを使用します。
まず第一に、MonitorEnter(jobject)
そしてMonitorExit(jobject)
この2つの機能を用いて操作する必要があるjobject
変数タイプ。
スレッド関数でjオブジェクトを作成するには、最初に考えたが、このようなものだったというstatic jobject jobject1 = env->NewIntArray(1);
静的参照変数を構築するために、しかし、操作がクラッシュを見つけるだろう、静的変数は、参照を作成するのに十分ではありません。
グローバル参照変数は、要件を満たすためです。 - 私が通じ、スレッド関数内で、試してみました
env->FindClass("classpath")
、そしてを通じてenv->AllocObject(jclass)
作成するjobject
変数を。
ランが見つかりenv->FindClass()
崩壊したとき。
子スレッドのenvので、カスタムクラスを直接取得することはできません、クラスのJDKを得ることができます。グローバル参照がさえてjclass
作成されjobject
、それはまた、崩壊します。 - 終了スレッド:
条件を満たすようにカスタマイズされているとき、あなたはできるpthread_exit()
コールという最初の出口モニターノートを終了する前に、スレッドを終了env->MonitorExit()
- Javaのスレッドが作成され、考えたことがあり、
MonitorEnter(jobject)
そしてMonitorExit(jobject)
また、相互に排他的で同期するために使用することができますか?試み。