Android开发之Thread类分析
在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create()
当我们想创建线程的时候,只需要继承于这个Thread类并实现虚函数thread_loop()即可。
frameworks/base/include/utils/threads.hclass Thread : virtual public RefBase{public:// 创建一个Thread对象,但是并不立即启动线程函数Thread(bool canCallJava = true);virtual ~Thread();// 开始启动线程函数,调用的是threadLoopvirtual 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()返回truebool exitPending() const;private:// 这是实际的线程函数,继承类必须实现它,// 返回true的话再次调用,返回false的话就会退出virtual bool threadLoop() = 0;// 禁止赋值Thread& operator = (const Thread&);// 内部类,被run函数调用,实际调用threadLoopstatic 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);elseres = 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,调用线程的run()方法,启动函数
更多相关文章
- Hello Android(安卓)- 调用打电话和发短信及intent一些其他用法
- Android的IPC机制之Binder详细介绍
- Android实现多线程下载文件的方法
- android源码分析流程-init.c
- Android类参考---Fragment(七)
- android加载gif图片的动画库
- Cocos2d-x 新版本中android震动
- 由rxjava中Flowable注释,引出的Reactive-Streams相关知识
- android ANR 问题