原生线程
1 示例项目
2 java线程
创建项目NativeThread
添加原生支持android tools--->add Native support
创建用户界面: activity_main.xml文件
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/edt_threads"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:focusable="true"
android:hint="@string/threads_edit"
android:inputType="number">
EditText>
<EditText
android:id="@+id/edt_iterations"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/iterations_edit"
android:inputType="number"/>
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btn_start"/>
<ScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txt_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
ScrollView>
LinearLayout>
字符串资源: string.xml文件
xmlversion="1.0"encoding="utf-8"?>
<resources>
<stringname="app_name">NativeThreadsstring>
<stringname="action_settings">Settingsstring>
<stringname="hello_world">NativeThreadsstring>
<stringname="threads_edit">Thread countstring>
<stringname="iterations_edit">Iteration countstring>
<stringname="btn_start">Start Threadsstring>
resources>
MainActivity.java文件
/**
* 原生线程
*
* @version
*
* @Description:
*
* @author
*
* @since 2014-7-9
*
*/
public class MainActivity extends Activity {
/* start button */
private Buttonbtn_start;
/* threads edit */
private EditTextedt_threads;
/* iterations edit*/
private EditTextedt_iterations;
/* log textView */
private TextViewtxt_log;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 本地方法 初始化原生代码
nativeInit();
// 实例化控件
findView();
}
/**
* 实例化控件
*/
private voidfindView() {
btn_start =(Button) this.findViewById(R.id.btn_start);
btn_start.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View v) {
intthreads = NativeThreadUtils.getIntNumber(edt_threads.getText().toString(), 0);
intiterations = NativeThreadUtils.getIntNumber(edt_iterations.getText().toString(),0);
if(threads > 0 && iterations > 0) {
//启动给定个数的线程进行迭代
startThreads(threads,iterations);
}
}
});
edt_threads =(EditText) this.findViewById(R.id.edt_threads);
edt_iterations= (EditText) this.findViewById(R.id.edt_iterations);
txt_log =(TextView) this.findViewById(R.id.txt_log);
}
/**
* 启动给定个数的线程进行迭代
*
* @param threads
*线程数
* @param iterations
*迭代数
*/
private voidstartThreads(int threads, final int iterations) {
javaThreads(threads,iterations);
}
/**
* 使用基于 java的线程
*
* @param threads
* @param iterations
*/
private voidjavaThreads(int threads, final int iterations) {
// 为每一个worker创建军基于java的线程
for (int i = 0; i < threads; i++) {
finalint id = i;
Threadthread = new Thread() {
@Override
publicvoid run() {
//
nativeWorker(id,iterations);
}
};
thread.start();
}
}
/**
* 原生线程回调
*
* @param message
*原生消息
*/
private voidonNativeMessage(final String message) {
runOnUiThread(newRunnable() {
@Override
publicvoid run() {
txt_log.append(message);
txt_log.append("\n");
}
});
}
@Override
public boolean onCreateOptionsMenu(Menumenu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@Override
protected voidonDestroy() {
// 释放原生资源
nativeFree();
super.onDestroy();
}
// 声明本地方法
/* 初始化本地方法 */
private native voidnativeInit();
/* 释放原生资源 */
private native voidnativeFree();
/**
* 原生worker
*
* @param id
* @param iterations
*/
private native voidnativeWorker(int id, int iterations);
/**
* 加载本地库
*/
static {
System.loadLibrary("NativeThreads");
}
}
生成c++头文件
Projectexplorer--->MainActivity.java--->run--->external tools--->generatec and c++ header file
将会在jni目录下生成cn_yue_nativethreads_MainActivity.h头文件,示例代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class cn_yue_nativethreads_MainActivity */
#ifndef _Included_cn_yue_nativethreads_MainActivity
#define _Included_cn_yue_nativethreads_MainActivity
#ifdef __cplusplus
extern"C" {
#endif
#undef cn_yue_nativethreads_MainActivity_MODE_PRIVATE
#define cn_yue_nativethreads_MainActivity_MODE_PRIVATE0L
#undefcn_yue_nativethreads_MainActivity_MODE_WORLD_READABLE
#definecn_yue_nativethreads_MainActivity_MODE_WORLD_READABLE 1L
#undefcn_yue_nativethreads_MainActivity_MODE_WORLD_WRITEABLE
#definecn_yue_nativethreads_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef cn_yue_nativethreads_MainActivity_MODE_APPEND
#define cn_yue_nativethreads_MainActivity_MODE_APPEND32768L
#undefcn_yue_nativethreads_MainActivity_MODE_MULTI_PROCESS
#definecn_yue_nativethreads_MainActivity_MODE_MULTI_PROCESS 4L
#undefcn_yue_nativethreads_MainActivity_BIND_AUTO_CREATE
#definecn_yue_nativethreads_MainActivity_BIND_AUTO_CREATE 1L
#undefcn_yue_nativethreads_MainActivity_BIND_DEBUG_UNBIND
#define cn_yue_nativethreads_MainActivity_BIND_DEBUG_UNBIND2L
#undefcn_yue_nativethreads_MainActivity_BIND_NOT_FOREGROUND
#definecn_yue_nativethreads_MainActivity_BIND_NOT_FOREGROUND 4L
#undefcn_yue_nativethreads_MainActivity_BIND_ABOVE_CLIENT
#define cn_yue_nativethreads_MainActivity_BIND_ABOVE_CLIENT8L
#undefcn_yue_nativethreads_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#definecn_yue_nativethreads_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undefcn_yue_nativethreads_MainActivity_BIND_WAIVE_PRIORITY
#define cn_yue_nativethreads_MainActivity_BIND_WAIVE_PRIORITY32L
#undefcn_yue_nativethreads_MainActivity_BIND_IMPORTANT
#definecn_yue_nativethreads_MainActivity_BIND_IMPORTANT 64L
#undefcn_yue_nativethreads_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define cn_yue_nativethreads_MainActivity_BIND_ADJUST_WITH_ACTIVITY64L
#undefcn_yue_nativethreads_MainActivity_CONTEXT_INCLUDE_CODE
#definecn_yue_nativethreads_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undefcn_yue_nativethreads_MainActivity_CONTEXT_IGNORE_SECURITY
#define cn_yue_nativethreads_MainActivity_CONTEXT_IGNORE_SECURITY2L
#undefcn_yue_nativethreads_MainActivity_CONTEXT_RESTRICTED
#definecn_yue_nativethreads_MainActivity_CONTEXT_RESTRICTED 4L
#undefcn_yue_nativethreads_MainActivity_RESULT_CANCELED
#definecn_yue_nativethreads_MainActivity_RESULT_CANCELED 0L
#undef cn_yue_nativethreads_MainActivity_RESULT_OK
#define cn_yue_nativethreads_MainActivity_RESULT_OK -1L
#undefcn_yue_nativethreads_MainActivity_RESULT_FIRST_USER
#definecn_yue_nativethreads_MainActivity_RESULT_FIRST_USER 1L
#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DISABLE
#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DIALER
#define cn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DIALER1L
#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SHORTCUT
#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
* 初始化本地方法
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeInit
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeInit(
JNIEnv *, jobject);
/*
* 释放本地资源
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeFree
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeFree(
JNIEnv *, jobject);
/*
* 原生worker
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeWorker
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeWorker(
JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
实现原生函数
/*
*cn_yue_nativethreads_MainActivity.cpp
*
* Created on: 2014-7-9
* Author: retacn
*
*/
#include
#include
#include"cn_yue_nativethreads_MainActivity.h"
//方法ID能被缓存
staticjmethodID gOnNativeMessage = NULL;
/*
* 初始化本地方法
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeInit
* Signature: ()V
*/
void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeInit(JNIEnv * env,
jobject obj) {
//如果方法没有被缓存
if (NULL == gOnNativeMessage) {
//从对象中取得类
jclass clazz = env->GetObjectClass(obj);
//为回调方法id
gOnNativeMessage=env->GetMethodID(clazz, "onNativeMessage", "(Ljava/lang/String;)V");
//如果没有找到方法
if (NULL == gOnNativeMessage) {
//获取异常类
jclass exceptionClazz = env->FindClass(
"java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to find methond");
}
}
}
/*
* 释放本地资源
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeFree
* Signature: ()V
*/
void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeFree(JNIEnv * env,
jobject obj) {
}
/*
* 原生worker
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeWorker
* Signature: (II)V
*/
void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeWorker(JNIEnv * env,
jobject obj, jint id, jint iterations) {
//循环给定的迭代次数
for (jint i = 0; i < iterations; i++) {
//准备消息
char message[26];
sprintf(message, "worker %d: iteration %d", id, i);
//来自c字符串的消息
jstring messageString = env->NewStringUTF(message);
//调用原生消息方法
env->CallVoidMethod(obj,gOnNativeMessage, messageString);
//检查是否发和异常
if (NULL != env->ExceptionOccurred()) {
break;
}
sleep(1);
}
}
更新android.mk构建脚本
LOCAL_PATH := $(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE := NativeThreads
LOCAL_SRC_FILES :=cn_yue_nativethreads_MainActivity.cpp
include$(BUILD_SHARED_LIBRARY)
3 posix线程
在原生代码中使用posix线程,需要添加#include
//成功返回0
Int pthread_create(pthread_t thread,//用该指针返回新线程的句柄
pthread_attr_tconst* cttr,//新线程属性
void*(*start_routine) (void*),//指向中线程启动程序的指针
void*arg);//
在示例中使用posix线程
A 声明原生方法
/* 使用原生posix线程 */
privatenativevoid posixThreads(int threads, int iterations);
B 重新生成头文件
/*
* Class: cn_yue_nativethreads_MainActivity
* Method: posixThreads
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_posixThreads
(JNIEnv *, jobject, jint, jint);
C 更新原生代码
添加#include
定义启动参数结构体
/*原生线程参数*/
structNativeWorkerArgs {
jintid;
jintiterations;
};
全局变量保存java vm和对象实例的全局引用
/*java虚拟机接口指针*/
staticJavaVM* gVm = NULL;
/*对象的全局引用*/
staticjobject gObj = NULL;
...
/**
* 取得java虚拟机接口指针
*/
jintJNI_OnLoad(JavaVM* vm, void* reserved) {
//缓存java虚拟机接口批针
gVm = vm;
return JNI_VERSION_1_4;
}
voidJava_cn_yue_nativethreads_MainActivity_nativeInit(JNIEnv * env,
jobject obj) {
//为对象实例创建一个全局引用
if (NULL == gObj) {
//创建全局变量
gObj =env->NewGlobalRef(obj);
if (NULL == gObj) {
goto exit;
}
}
...
}
在freeNative中删除全局引用
//删除全局引用
if (NULL != gObj) {
env->DeleteGlobalRef(gObj);
gObj = NULL;
}
为原生worker线程添加启动程序
/**
* 为原生worker添加启动程序
*/
staticvoid* nativeWorkerThread(void* args) {
JNIEnv* env = NULL;
//将当前线程符加到java虚拟机上
if (0 == gVm->AttachCurrentThread(&env,NULL)) {
//取得原生worker线程参数
NativeWorkerArgs* nativeWorkerArgs = (NativeWorkerArgs*) args;
//在线程上下文中运行wroker
Java_cn_yue_nativethreads_MainActivity_nativeWorker(env,gObj,
nativeWorkerArgs->id,nativeWorkerArgs->iterations);
//释放原生线程worker线程参数
delete nativeWorkerArgs;
//从java虚拟机中分离当前线程
gVm->DetachCurrentThread();
}
return (void*) 1;
}
实现posixThread原生方法
/*
* posix线程
* Class: cn_yue_nativethreads_MainActivity
* Method: posixThreads
* Signature: (II)V
*/
voidJava_cn_yue_nativethreads_MainActivity_posixThreads(JNIEnv* env,
jobject obj, jint threads, jint iterations) {
//为每一个worker创建一个posix线程
for (jint i = 0; i < threads; i++) {
NativeWorkerArgs* nativeWorkerArgs = newNativeWorkerArgs();
nativeWorkerArgs->id= i;
nativeWorkerArgs->iterations = iterations;
pthread_t thread;
//创建一个新线程
int result = pthread_create(&thread, NULL, nativeWorkerThread,
(void*) nativeWorkerArgs);
if (0 != result) {
//获取异常类
jclass exceptionClazz = env->FindClass(
"java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to createthread!");
}
}
}
4 从posix线程返回结果
Java_cn_yue_nativethreads_MainActivity_posixThreads是在线程执行后立即返回,通过pthread_join可以合其在线程结束后返回
//函数原型 成功返回结果为0
intpthread_join(pthread_t thid,//目标线程
void ** ret_val);//指向空指针的指针,从启动程序中取得返回值
更改示例程序
/*
* posix线程
* Class: cn_yue_nativethreads_MainActivity
* Method: posixThreads
* Signature: (II)V
*/
voidJava_cn_yue_nativethreads_MainActivity_posixThreads(JNIEnv* env,
jobject obj, jint threads, jint iterations) {
//线程句柄
pthread_t* handles = newpthread_t(threads);
//为每一个worker创建一个posix线程
for (jint i = 0; i < threads; i++) {
NativeWorkerArgs* nativeWorkerArgs = newNativeWorkerArgs();
nativeWorkerArgs->id= i;
nativeWorkerArgs->iterations = iterations;
pthread_t thread;
//创建一个新线程
int result = pthread_create(&handles[i], NULL, nativeWorkerThread,
(void*) nativeWorkerArgs);
if (0 != result) {
//获取异常类
jclass exceptionClazz = env->FindClass(
"java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to createthread!");
goto exit;
}
}
//等待线程终止
for (jint i = 0; i < threads; i++) {
void* result = NULL;
//连接每个句柄
if (0 != pthread_join(handles[i], &result)) {
//获取异常类
jclass exceptionClazz = env->FindClass(
"java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to jointhread!");
} else {
//准备message
char message[26];
sprintf(message, "worker %d returned %d", i, result);
//
jstring messageString = env->NewStringUTF(message);
//调用原生消息方法
env->CallVoidMethod(obj,gOnNativeMessage, messageString);
//检查是否产生异常
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
}
}
exit: return;
}
5 posix线程同步
两种最常用的同步机制:
A 互斥锁(mutexes) pthread_mutex_t展示互斥锁到原生代码
使用互斥锁同步posix线程
初始化互斥锁
intpthread_mutex_init(pthread_mutex_t *mutex,//互斥变量
constpthread_mutexattr_t *attr);//互斥锁定义
如果第二个参数为空,则使用默认属性如下:
#define__PTHREAD_MUTEX_INIT_VALUE0
#definePTHREAD_MUTEX_INITIALIZER {__PTHREAD_MUTEX_INIT_VALUE}
如果初始化成功互斥锁处于打开状态 ,返回值为0
锁定互斥锁
intpthread_mutex_lock(pthread_mutex_t *mutex);//参数为互斥锁指针
解锁互斥锁
intpthread_mutex_destroy(pthread_mutex_t *mutex);//参数为互斥锁指针
在示例代码中使用互斥锁
添加互斥锁到原生代码:
/*互斥锁*/
staticpthread_mutex_tmutex;
在Java_cn_yue_nativethreads_MainActivity_nativeInit函数中初始化互斥锁
//初始化互斥锁
if (0 != pthread_mutex_init(&mutex, NULL)) {
//获取异常类
jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable toinitialize mutex!");
goto exit;
}
在Java_cn_yue_nativethreads_MainActivity_nativeFree函数中销毁互斥锁
//销毁互斥锁
if (0 != pthread_mutex_destroy(&mutex)) {
//获取异常类
jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to destorymutex!");
}
在Java_cn_yue_nativethreads_MainActivity_nativeWorker函数中使用互斥锁
/*
* 原生worker
* Class: cn_yue_nativethreads_MainActivity
* Method: nativeWorker
* Signature: (II)V
*/
voidJava_cn_yue_nativethreads_MainActivity_nativeWorker(JNIEnv * env,
jobject obj, jint id, jint iterations) {
//锁定互斥锁
if (0 != pthread_mutex_lock(&mutex)) {
//获取异常类
jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to lock mutex!");
goto exit;
}
//循环给定的迭代次数
for (jint i = 0; i < iterations; i++) {
//准备消息
char message[26];
sprintf(message, "worker %d: iteration %d", id, i);
//来自c字符串的消息
jstring messageString = env->NewStringUTF(message);
//调用原生消息方法
env->CallVoidMethod(obj,gOnNativeMessage, messageString);
//检查是否发和异常
if (NULL != env->ExceptionOccurred()) {
break;
}
sleep(1);
}
//解锁互斥锁
if (0 != pthread_mutex_unlock(&mutex)) {
//获取异常类
jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
//抛出异常
env->ThrowNew(exceptionClazz,"Unable to unlock mutex!");
}
exit: return;
}
运行示例程序,得到锁的线程会先执行,以此类推
B 信号量(semaphores)
使用信号量同步posix线程
添加头文件#include
初始化信号量
externintsem_init(sem_t *sem,//信号量变量指针
int pshared,//共享标志
unsignedint value);//初始值
锁定信号量
externintsem_wait(sem_t *);
解锁信号量
externintsem_post(sem_t *);
销毁信号量
externintsem_destroy(sem_t *);
6 posix线程的优先级和调度策略
最常使用的调度策略:
SCHED_FIFO:先进先出,基于线程进入列表的时间进行排序,也可以基于优先级
SCHED_RR:循环轮转,是线程执行时间加以限制的SCHED_FIFO,其目的避免线程独占可用的cpu时间
以上调度策略在sched.h头文件中定义,可以在pthread_create创建线程时,用pthread_attr_t的sched_policy域来定义调度策略
也可以在运行时调用,
intpthread_setschedparam(pthread_t thid,//目标线程指针
int poilcy,//调度策略
structsched_paramconst * param);//参数
posixThread的优先级
在pthread_create创建线程时,用pthread_attr_t的sched_policy域来定义调度优先级,也可以在运行时调用,intpthread_setschedparam函数参数中的param中提供优先级
Sched_get_priority_max和Sched_get_priority_min来查询优先级的最大最小值