[置顶] Android开发之Thread类分析
在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create()
当我们想创建线程的时候,只需要继承于这个Thread类并实现虚函数thread_loop()即可。
frameworks/base/include/utils/threads.h
class Thread : virtual public RefBase
{
public:
// 创建一个Thread对象,但是并不立即启动线程函数
Thread(bool canCallJava = true);
virtual ~Thread();
// 开始启动线程函数,调用的是threadLoop
virtual status_t run(const char*name = 0, int32_t prority = PRIORITY_DEFAULT,
size_t stack = 0);
// 申请退出这个线程
virtual void requestExit();
virtual status_t readyToRun();
// 调用requestExit()等待直到这个线程退出
status_t requestExitAndWait();
// 等待直到线程退出,如果没有启动立即返回
status_t join();
protected:
// 如果调用了requestExit()返回true
bool exitPending() const;
private:
// 这是实际的线程函数,继承类必须实现它,
// 返回true的话再次调用,返回false的话就会退出
virtual bool threadLoop() = 0;
// 禁止赋值
Thread& operator = (const Thread&);
// 内部类,被run函数调用,实际调用threadLoop
static int _threadLoop(void* user);
const bool mCanCallJava;
thread_id_t mThread; // thread_id_t 其实是 void*类型
mutable Mutex mLock;
Condition mThreadExitedCondition;
status_t mStatus;
// 注意:所以操作这两个变量的地方都需要上锁
volatile bool mExitPending;
volatile bool mRunning;
sp<Thread> mHoldSelf;
};
我们首先看下Thread类的构造函数:
Thread::Thread(bool canCallJava)
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thrad::mLock"),
mStatus(NO_ERROR),
mExitPending(false), mRunnig(false)
{}
真正启动线程的函数:
status_t Thread::run(const char*name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if(mRunnig)
return INVALID_OPERATION;
mState = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
mHoldSelf = this; // 保存着当前对象的引用
mRunning = true;
if (mCanCallJava)
res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);
else
res = androidCreateRawThreadEtc(_threadLoop, this, name,
priority, stack, &mThread);
if(res == false) {
mStatus = UNKNOWN_ERROR;
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear();
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
这里有个判断mCanCallJava是个什么东西?接着往下看
inline bool createThreadEtc(thread_func_t entryFunction, void* userData,
const char* threadName = "android:unnamed_thread",
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
thread_id_t *threadId = 0)
{
return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority,
threadStackSize, threadId) ? true : false;
}
int androidCreateThreadEtc(thread_func_t entryFunction,
void* userData,
const char* threadName,
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
thread_id_t *threadId = 0)
{
return gCreateThreadFn(entryFunction, userData, threadName, threadPriority,
threadStackSize, threadId);
}
我们看到最后调用的是gCreateThreadFn这个函数,而gCreateThreadFn是个全局的函数指针,
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
这里默认给它赋值为 androidCreateRawThreadEtc,这跟前面调用的是一样的???
既然是函数指针肯定有给它赋值的地方:
void androidSetCreateThreadFunc(android_create_thread_fn func)
{
gCreateThreadFn = func;
}
那这个函数在什么地方调用的呢?又给它赋什么值了呢?
我们找到了再AndroidRuntime类里面启动虚拟机的地方:
int androidRuntime::startReg(JNIEnv* env)
{
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
return 0;
}
这样如果我们的mCanCallJava如果为true的话,调用的就是:
int AndroidRuntime::javaCreateThreadEtc(android_thread_func_t entryFunction,
void* userData,
const char* threadName,
int32_t threadPriority,
suze_t threadStackSize,
android_thread_id_t *threadId)
{
void** args = (void**)malloc(3*sizeof(void*));
args[0] = (void*)entryFunction;
args[1] = userData;
args[2] = (void*)strdup(threadName);
return androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args.
threadName, threadPriority, threadStackSize, threadId);
}
最后调用的还是同一个创建线程的函数只是回调函数不一样,这里变成了AndroidRuntime::javaThreadShell
int AndroidRuntime::javaCreateThreadEtc(void* args)
{
voir* start = ((void**)args)[0];
voir* userData = ((void**)args)[1];
voir* name = ((void**)args)[2];
free(args);
JNIEnv* env; javaAttachThread(name, &env);
result = (*(android_thead_func_t)start)(userData);
javaDetachThread(); free(name);
return result;
}
这里线程函数javaThreadShell里面还是调用前面我们的_threadLoop函数,只不过在调用之前,调用
了javaAttachThread()将线程attach到JNI环境中去了,这样线程函数就可以调用JNI函数,最后线程
函数退出之后再调用javaDetachThread()退出JNI环境。
现在进入线程函数_threadLoop(),这是一个static函数
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast<Thread*>(user);
sp<Thead> strong(self->mHoldSelf);
wp<Thead> weak(strong);
self->mHoldSelf.clear(); bool first = true; do { // 进入一个循环,通过判断返回值和内部退出标志位决定是否退出线程
bool result;
if (fisr) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPendind()) { // 检查是否退出
result = self->threadLoop(); // 调用实际线程函数
}
} else {
result = self->threadLoop();
} {
Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
self-mRunning = false;
self->mThread = thread_ir_t(-1);
self->mThreadExitedCondition.broadcast();
break;
} }
strong.clear();
strong = weak.promote();
} while(strong != 0);
return 0;
}
在这里线程退出的条件为:
1)result = true 意味着子类在实现的threadLoop函数中返回false,这样线程就主动退出了
2)mExidPendding = true 这个变量值由Thread类的requestExit函数设置,这样线程就被动退出了。
最后如果线程退出了需要进行些去初始化操作,设置线程运行状态,广播告知其他关心这个线程的对象。
最后,如果我们想使用线程类:
1)创建一个类如MyThread,继承与Thead类
2)在MyThread类中实现父类的纯虚函数threadLoop,也就是我们调用pthread_create时传入的线程函数。
3)定义一个MyThread变量 thread,调用线程的start()方法,启动函数
[置顶] Android开发之Thread类分析的更多相关文章
- Android开发之Thread类分析 (转载)
转自:http://blog.csdn.net/llping2011/article/details/9706599 在我们Linux系统中创建线程函数为:pthread_create(),在Andr ...
- [置顶] Android开发之serviceManager分析
Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...
- [置顶] Android开发之MediaPlayerService服务详解(一)
前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...
- [置顶] Android开发之XML文件的解析
Android系统开发之XML文件的解析 我们知道Http在网络传输中的数据组织方式有三种分别为:XML方式.HTML方式.JSON方式.其中XML为可扩展标记语言,如下: <?xml vers ...
- [置顶] Android开发之ProcessState和IPCThreadState类分析
在Android中ProcessState是客户端和服务端公共的部分,作为Binder通信的基础,ProcessState是一个singleton类,每个 进程只有一个对象,这个对象负责打开Binde ...
- Android开发之MediaRecorder类详解
MediaRecorder类介绍: MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频,摄像头采集图片信息. MediaRecorder主要函 ...
- Android开发之MediaPlayer类
官网关于MediaPlayer类的使用简介:
- Android开发之PackageManager类
PackageManger,可以获取到手机上所有的App,并可以获取到每个App中清单文件的所有内容. 设置应用程序版本号在应用程序的manifest文件中定义应用程序版本信息.2个必须同时定义的属性 ...
- Android开发之Path类使用详解,自绘各种各样的图形!
玩过自定义View的小伙伴都知道,在View的绘制过程中,有一个类叫做Path,Path可以帮助我们实现很多自定义形状的View,特别是配合xfermode属性来使用的时候.OK,那我们今天就来看看P ...
随机推荐
- SharePoint 2013 禁用搜索服务
原文:SharePoint 2013 禁用搜索服务 前言,在SharePoint2013中,对于硬件需求的提升,让我们虚机里安装总是一筹莫展,尤其开启了搜索服务以后,对于内存的消耗就更加严重,尤其对于 ...
- 跟Bob大叔观OO原则
上篇总结了经典的23种 设计模式,详细的解读后期会陆续的详细揭开.使用设计模式的根本原因就是为了增强代码的复用性和可维护性.而面向对象是实现代码复用的有效途径,所以这里有必要了解一下OO的基本思想和原 ...
- Notification使用以及PendingIntent.getActivity() (转)
public void sendNotification(Context ctx,String message) { //get the notification manager String ns ...
- hdu 4975 最大流问题解决队伍和矩阵,利用矩阵dp优化
//刚開始乱搞. //网络流求解,假设最大流=全部元素的和则有解:利用残留网络推断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环.见上一篇4888 //至少四个点构成的环,另外一种是用 ...
- 我的MYSQL学习心得(三)
原文:我的MYSQL学习心得(三) 我的MYSQL学习心得(三) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(四) 我的MYSQL学习心得(五) 我的MYSQL ...
- js中document.write()使用方法
<script> var hrf = window.location.href; if(hrf.indexOf('change')>0){ ...
- 从头学起android<GridView网格视图.二十八.>
GridView基于组件的网络格所有的形式的组分的,例如:当制作专辑,所有的图片将在相同的尺寸在不同的显示格在孩子,是否能够依靠这个组件完成.此组件的继承结构参见例如下面: java.lang.Obj ...
- RegisterStartupScript和RegisterClientScriptBlock区别
RegisterStartupScript(key, script) RegisterClientScriptBlock(key, script) 这两个方法的作用都是从前台向后台写脚本,且都接受两个 ...
- MyEclipse下一个XFire发展Webservice示例
最近的研究JAVA发展Webservice.网络发现几个热门选择AXIS.XFire.CFX(XFire下一代),打开前几天对这篇文章比较三种选择,他们已经有了一些概念. 样本,以确定自己的实践 在開 ...
- iOS开发分析"秘密"App内容页面的效果(两)
@我前几天写的"秘密"的Cell制品的效果,想要的效果还是有差距,并且扩展性非常不好,于是重写封装,把总体视图都放到scrollView中,基本是和secret app 一模一样的 ...