zoukankan      html  css  js  c++  java
  • Android开发之Thread类分析 (转载)

      转自:http://blog.csdn.net/llping2011/article/details/9706599

           在我们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,调用线程的run()方法,启动函数 
  • 相关阅读:
    Navicat 12 的安装和破解
    Intellij ide 2017.2新建javaweb项目,并且部署
    javaSE 打印九九乘法表
    jquery.validate remote 和 自定义验证方法
    MySQL命令行导出数据库
    从cookie中取值$.cookie()
    23个MySQL常用查询语句
    正则表达式限制文本框只能输入数字,小数点,英文字母,汉字
    jquery从零开始学----选择器
    文件上传利器SWFUpload使用指南
  • 原文地址:https://www.cnblogs.com/lance-ehf/p/4016231.html
Copyright © 2011-2022 走看看