精华内容
下载资源
问答
  • Android ThreadthreadLoop方法

    千次阅读 2018-04-12 17:27:54
    Android Framework中的线程Thread及它的threadLoop方法 在Framework中的Thread普遍的特点就是有一个 threadLoop方法。它到底是怎么循环起来的。 Android中java世界的Thread 先来看看java是怎么创建一个线程的。...

    Android Framework中的线程Thread及它的threadLoop方法

    在Framework中的Thread普遍的特点就是有一个 threadLoop方法。它到底是怎么循环起来的。

    Android中java世界的Thread

    先来看看java是怎么创建一个线程的。这个是最舒服的,也是我最熟悉的。

    new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                    ...
            }
    }).start();

    当然,你也可以在android中创建一个消息循环的HandlerThread

    HandlerThread mThread = new HandlerThread("test");
    mThread.start();
    Handler mHandler = new Handler(mThread.getLooper()){
    
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stubsuper.handleMessage(msg);
            }
    };

    上面中通过mHandler发送消息就可以在mThread中处理了,并且这个mThread不是UIThread,不会阻塞主线程。

    Linux下c语言的Thread

    java世界的Thread很方便,那么c呢?
    Android基于linux所以,多线程编程也应该基于linux下的多线程。linux下的c语言用pthread。大家可以看这篇文章。
    linux下C/C++,多线程pthread
    我把里面的例子改良了一下
    test.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    void *test(void *ptr)
    {
        int i;
        for(i=0;i<8;i++)
        {
            printf("the pthread running ,count: %d\n",i);
            sleep(1); 
        }
    
    }
    
    
    int main(void)
    {
        pthread_t pId;
        int i,ret;
        ret = pthread_create(&pId,NULL,test,NULL);
    
        if(ret != 0)
        {
            printf("create pthread error!\n");
            exit(1);
        }
    
        for(i=0;i < 5;i++)
        {
            printf("main thread running ,count : %d\n",i);
            sleep(1);
        }
    
        printf("main thread will exit when pthread is over\n");
        pthread_join(pId,NULL);
        printf("main thread  exit\n");
    
        return0;
    
    }

    然后编译

    gcc -o test test.c -lpthread./test
    

    运行结果如下:

    main thread running ,count : 0the pthread running ,count: 0
    main thread running ,count : 1the pthread running ,count: 1
    main thread running ,count : 2the pthread running ,count: 2
    main thread running ,count : 3the pthread running ,count: 3
    main thread running ,count : 4the pthread running ,count: 4
    main thread will exit when pthread isoverthe pthread running ,count: 5the pthread running ,count: 6the pthread running ,count: 7
    main thread  exit

    例子比较简单,主要是创建一个线程,然后主线程等待子线程运行完毕再退出。

    Android Framework中的Thread

    下面焦点回到文章的主题当中,我们来看看Framework中常用的Thread是个何种形态。
    先看看活生生的例子。
    在源码中搜索threadLoop,当然也可以搜索thread,然后随便挑选一个Thread子类进行研究。这里挑了
    /frameworks/av/services/audioflinger/AudioWatchdog.h

    #ifndef AUDIO_WATCHDOG_H
    #define AUDIO_WATCHDOG_H
    #include <time.h>
    #include <utils/Thread.h>
    
    namespace android {
    
    ......
    
    class AudioWatchdog : public Thread {
    
    public:
        AudioWatchdog(unsigned periodMs = 50) : Thread(false/*canCallJava*/), mPaused(false),
                mPeriodNs(periodMs * 1000000), mMaxCycleNs(mPeriodNs * 2),
                // mOldTs// mLogTs initialized below
                mOldTsValid(false), mUnderruns(0), mLogs(0), mDump(&mDummyDump)
            {
                #define MIN_TIME_BETWEEN_LOGS_SEC 60// force an immediate log on first underrun
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
            }
        virtual         ~AudioWatchdog() { }
        // Do not call Thread::requestExitAndWait() without first calling requestExit().
        // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.virtualvoid        
        requestExit();
    
        // FIXME merge API and implementation with AudioTrackThreadvoid            
        pause();        // suspend thread from execution at next loop boundaryvoid            
        resume();       // allow thread to execute, if not requested to exit
        // Where to store the dump, or NULL to not updatevoid            
        setDump(AudioWatchdogDump* dump);
    
    private:
        virtual bool threadLoop();
    
        Mutex           mMyLock;        // Thread::mLock is private
        Condition       mMyCond;        // Thread::mThreadExitedCondition is privatebool            mPaused;        // whether thread is currently paused
    
        ......
    };
    
    }   // namespace android#endif  // AUDIO_WATCHDOG_H

    我们可以看到AudioWatchDog确实是Thread的子类,那好,下面看实现。
    /frameworks/av/services/audioflinger/AudioWatchdog.cpp

    #define LOG_TAG "AudioWatchdog" //#define LOG_NDEBUG 0
    #include <utils/Log.h>
    #include "AudioWatchdog.h"
    namespace android {
    
    void AudioWatchdogDump::dump(int fd)
    {
        char buf[32];
        if (mMostRecent != 0) {
            // includes NUL terminator
            ctime_r(&mMostRecent, buf);
        } else {
            strcpy(buf, "N/A\n");
        }
        fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
                mUnderruns, mLogs, buf);
    }
    
    bool AudioWatchdog::threadLoop()
    {
        {
            AutoMutex _l(mMyLock);
            if (mPaused) {
                mMyCond.wait(mMyLock);
                // ignore previous timestamp after resume()
                mOldTsValid = false;
                // force an immediate log on first underrun after resume()
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
                // caller will check for exitPending()returntrue;
            }
        }
        struct timespec newTs;
        int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
        if (rc != 0) {
            pause();
            returnfalse;
        }
        if (!mOldTsValid) {
            mOldTs = newTs;
            mOldTsValid = true;
            returntrue;
        }
        time_t sec = newTs.tv_sec - mOldTs.tv_sec;
        long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
        if (nsec < 0) {
            --sec;
            nsec += 1000000000;
        }
        mOldTs = newTs;
        // cycleNs is same as sec*1e9 + nsec, but limited to about 4 seconds
        uint32_t cycleNs = nsec;
        if (sec > 0) {
            if (sec < 4) {
                cycleNs += sec * 1000000000;
            } else {
                cycleNs = 4000000000u;
            }
        }
        mLogTs.tv_sec += sec;
        if ((mLogTs.tv_nsec += nsec) >= 1000000000) {
            mLogTs.tv_sec++;
            mLogTs.tv_nsec -= 1000000000;
        }
        if (cycleNs > mMaxCycleNs) {
            mDump->mUnderruns = ++mUnderruns;
            if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) {
                mDump->mLogs = ++mLogs;
                mDump->mMostRecent = time(NULL);
                ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u",
                    mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs);
                mLogTs.tv_sec = 0;
                mLogTs.tv_nsec = 0;
            }
        }
        struct timespec req;
        req.tv_sec = 0;
        req.tv_nsec = mPeriodNs;
        rc = nanosleep(&req, NULL);
        if (!((rc == 0) || (rc == -1 && errno == EINTR))) {
            pause();
            returnfalse;
        }
        returntrue;
    }
    
    void AudioWatchdog::requestExit()
    {
        // must be in this order to avoid a race condition
        Thread::requestExit();
        resume();
    }
    
    void AudioWatchdog::pause()
    {
        AutoMutex _l(mMyLock);
        mPaused = true;
    }
    
    void AudioWatchdog::resume()
    {
        AutoMutex _l(mMyLock);
        if (mPaused) {
            mPaused = false;
            mMyCond.signal();
        }
    }
    
    void AudioWatchdog::setDump(AudioWatchdogDump *dump)
    {
        mDump = dump != NULL ? dump : &mDummyDump;
    }
    
    }   // namespace android

    很明显,它的核心方法就是threadLoop(),但是它是怎么启动的呢?又是怎么循环运行的呢?带着疑问我又在源码中搜索关键字AudioWatchdog
    结果发现有两个地方引用了。

    /frameworks/av/services/audioflinger/AudioFlinger.h
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    在AudioFlinger.h中MixerThread中有个AudioWatchdog的sp对象

     class MixerThread : public PlaybackThread {
        public:
            MixerThread (const sp<AudioFlinger>& audioFlinger,
                         AudioStreamOut* output,
                         audio_io_handle_t id,
                         audio_devices_t device,
                         type_t type = MIXER);
            virtual             ~MixerThread();
    
    
        protected:
                        AudioMixer* mAudioMixer;    // normal mixerprivate:
                        sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread
        };

    我们再看代码
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
            audio_io_handle_t id, audio_devices_t device, type_t type)
            :PlaybackThread(audioFlinger, output, id, device, type),
            // mAudioMixer below// mFastMixer below
            mFastMixerFutex(0)
            // mOutputSink below// mPipeSink below// mNormalSink below
    {
    
    ......
    #ifdef AUDIO_WATCHDOG
            // create and start the watchdog
            mAudioWatchdog =new AudioWatchdog();
            mAudioWatchdog->setDump(&mAudioWatchdogDump);
            mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
            tid = mAudioWatchdog->getTid();
            err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
            if (err !=0) {
                ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                        kPriorityFastMixer, getpid_cached, tid, err);
            }
    #endif......
    }

    删掉不相关代码,我们看到AudioWatchdog对象确实创建了,并且调用了它的run方法。在java中Thread的run方法就是启动, 这个也应该如此。但是如之前的源码所示AudioWatchdog.cpp中并没有实现run方法,怎么办呢?别紧张,它还有父类Thread.

    /frameworks/native/include/utils/Thread.h

    #ifndef _LIBS_UTILS_THREAD_H
    #define _LIBS_UTILS_THREAD_H
    #include <stdint.h>
    #include <sys/types.h>
    #include <time.h>
    #if defined(HAVE_PTHREADS)
    # include <pthread.h>
    #endif
    #include <utils/Condition.h>
    #include <utils/Errors.h>
    #include <utils/Mutex.h>
    #include <utils/RefBase.h>
    #include <utils/Timers.h>
    #include <utils/ThreadDefs.h>// ---------------------------------------------------------------------------
    namespace android {
    // ---------------------------------------------------------------------------
    
    class Thread : virtual public RefBase
    {
    public:
        // Create a Thread object, but doesn't create or start the associated
        // thread. See the run() method.
        Thread(bool canCallJava = true);
        virtual             ~Thread();
    
        // Start the thread in threadLoop() which needs to be implemented.virtual status_t  run(    constchar* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0);
    
        // Ask this object's thread to exit. This function is asynchronous, when the// function returns the thread might still be running. Of course, this// function can be called from a different thread.virtualvoid        requestExit();
    
        // Good place to do one-time initializationsvirtual status_t    readyToRun();
    
        // Call requestExit() and wait until this object's thread exits.// BE VERY CAREFUL of deadlocks. In particular, it would be silly to call// this function from this object's thread. Will return WOULD_BLOCK in// that case.
                status_t    requestExitAndWait();
    
        // Wait until this object's thread exits. Returns immediately if not yet running.// Do not call from this object's thread; will return WOULD_BLOCK in that case.
                status_t    join();
    
    #ifdef HAVE_ANDROID_OS// Return the thread's kernel ID, same as the thread itself calling gettid() or// androidGetTid(), or -1 if the thread is not running.
                pid_t       getTid() const;
    #endifprotected:
        // exitPending() returns trueifrequestExit() has been called.
                boolexitPending() const;
    
    private:
        // Derived class must implement threadLoop(). The thread starts its life
        // here. There are two ways of using the Thread object:
        // 1) loop: if threadLoop() returns true, it will be called again if
        //          requestExit() wasn't called.
        // 2) once: if threadLoop() returns false, the thread will exit upon return.
        virtual bool threadLoop() = 0;
    
    private:
        Thread& operator=(const Thread&);
        staticint             _threadLoop(void* user);
        constbool            mCanCallJava;
        // always hold mLock when reading or writing
                thread_id_t     mThread;
        mutable Mutex           mLock;
                Condition       mThreadExitedCondition;
                status_t        mStatus;
        // note that all accesses of mExitPending and mRunning need to hold mLockvolatilebool           mExitPending;
        volatilebool           mRunning;
                sp<Thread>      mHoldSelf;
    #ifdef HAVE_ANDROID_OS// legacy for debugging, not used by getTid() as it is set by the child thread// and so is not initialized until the child reaches that point
                pid_t           mTid;
    #endif
    };
    
    
    }; // namespace android// ---------------------------------------------------------------------------#endif // _LIBS_UTILS_THREAD_H// 

    可以看到确实有run方法。
    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
    Mutex::Autolock _l(mLock);

    if (mRunning) {
        // thread already started
        return INVALID_OPERATION;
    }
    
    // reset status and exitPending to their default value, so we can
    //try again after an error happened (either below, orin readyToRun())
    mStatus = NO_ERROR;
    mExitPending = false;
    mThread = thread_id_t(-1);
    
    // hold a strong reference on ourself
    mHoldSelf = this;
    
    mRunning = true;
    
    bool res;
    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;   // something happened!
        mRunning = false;
        mThread = thread_id_t(-1);
        mHoldSelf.clear();  //"this" may have gone away after this.
    
        return UNKNOWN_ERROR;
    }
    
    // Do not refer to mStatus here: The thread is already running (may, in fact
    // already have exited with a valid mStatus result). The NO_ERROR indication
    // here merely indicates successfully starting the thread and does not// imply successful termination/execution.
    return NO_ERROR;
    
    // Exiting scope of mLock is a memory barrier and allows new thread to run
    

    }

    run()方法中有这么一段

    if (mCanCallJava) {
            res = createThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        } else {
            res = androidCreateRawThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        }

    mCanCallJava的意思是能不能被JNI层调用,然后根据值去创建Thread,这里有两个分支,我们就选择createThreadEtc()
    最终代码会走到这里

    int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                                   void *userData,
                                   const char* threadName,
                                   int32_t threadPriority,
                                   size_t threadStackSize,
                                   android_thread_id_t *threadId)
    {
        ......
            entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
            userData = t;
        }
    #endifif (threadStackSize) {
            pthread_attr_setstacksize(&attr, threadStackSize);
        }
    
        errno = 0;
        pthread_t thread;
        int result = pthread_create(&thread, &attr,
                        (android_pthread_entry)entryFunction, userData);
        pthread_attr_destroy(&attr);
        if (result != 0) {
            ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n""(android threadPriority=%d)",
                entryFunction, result, errno, threadPriority);
            return0;
        }
    
        ......
        return1;
    }

    删除了不相关代码,大家看看是不是很熟悉啊。我在文章开始的部分就写出了linux下c语言pthread创建线程的例子,大家可以回头看看。也就 是pthread_create()。这里面传进来的entryFunction是Thread中的_threadLoop()

    int Thread::_threadLoop(void* user)
    {
        Thread* const self= static_cast<Thread*>(user);
    
        sp<Thread> strong(self->mHoldSelf);
        wp<Thread> weak(strong);
        self->mHoldSelf.clear();
    
    #ifdef HAVE_ANDROID_OS
        // this is very useful for debugging with gdbself->mTid = gettid();
    #endif
    
        bool first =true;
    
        do {
            bool result;
            if (first) {
                first =false;
                self->mStatus =self->readyToRun();
                result = (self->mStatus == NO_ERROR);
    
                if (result &&!self->exitPending()) {
                    // Binder threads (and maybe others) rely on threadLoop// running at least once after a successful ::readyToRun()// (unless, of course, the thread has already been asked to exit// at that point).// This is because threads are essentially used like this://   (new ThreadSubclass())->run();// The caller therefore does not retain a strong reference to// the thread and the thread would simply disappear after the// successful ::readyToRun() call instead of entering the// threadLoop at least once.
                    result =self->threadLoop();
                }
            } else {
                result =self->threadLoop();
            }
    
            // establish a scope for mLock
            {
            Mutex::Autolock _l(self->mLock);
            if (result ==false||self->mExitPending) {
                self->mExitPending =true;
                self->mRunning =false;
                // clear thread ID so that requestExitAndWait() does not exit if// called by a new thread using the same thread ID as this one.self->mThread = thread_id_t(-1);
                // note that interested observers blocked in requestExitAndWait are// awoken by broadcast, but blocked on mLock until break exits scopeself->mThreadExitedCondition.broadcast();
                break;
            }
            }
    
            // Release our strong reference, to let a chance to the thread// to die a peaceful death.
            strong.clear();
            // And immediately, re-acquire a strong reference for the next loop
            strong = weak.promote();
        } while(strong !=0);
    
        return0;
    }

    _threadLoop()这个方法就是Thread的最大秘密,它是一个while循环。
    1、创建线程时,会sp和wp一次线程本身。
    2、如果是第一次执行会运行线程的readyToRun()方法,再执行threadLoop(),否则,直接运行threadLoop()。
    3、threadLoop()方法有返回值,如果threadLoop()返回false的时候,线程会做清理工作,然后退出while循环,结束运行。

    所以在这里,我开始时的疑问—为什么线程Thread中的threadLoop()能够循环处理数据就到此做了说明。Thread被创 建,Thread中的run被调用,__threadLoop()被调用,readyToRun()被调用,然后循环调用threadLoop()。并且 在threadLoop()返回false时,可以退出循环。

    特殊情况

    有的时候Android Framework中Thread的run()方法很难发现在哪里被调用。如SurfaceFlinger它也是一个Thread子类。在源码中搜索可以发现它的创建位置

    class SurfaceFlinger : public BinderService<SurfaceFlinger>,
                           public BnSurfaceComposer,
                           private IBinder::DeathRecipient,
                           private Thread,
                           private HWComposer::EventHandler
    {
    public:
        staticcharconst* getServiceName() {
            return"SurfaceFlinger";
        }
    
        SurfaceFlinger();
    
    
        /* ------------------------------------------------------------------------
         * Thread interface
         */virtualbool threadLoop();
        virtual status_t readyToRun();
        virtualvoid onFirstRef();
    
    
    };
    
    // ---------------------------------------------------------------------------
    }; // namespace android#endif // ANDROID_SURFACE_FLINGER_H

    去找它创建的地方
    /frameworks/base/cmds/system_server/library/system_init.cpp

    extern"C" status_t system_init()
    {
        ALOGI("Entered system_init()");
    
        sp<ProcessState> proc(ProcessState::self());
    
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p\n", sm.get());
    
    
    
        char propBuf[PROPERTY_VALUE_MAX];
        property_get("system_init.startsurfaceflinger", propBuf, "1");
        if (strcmp(propBuf, "1") == 0) {
            // Start the SurfaceFlinger
            SurfaceFlinger::instantiate();
        }
    
    
        // And now start the Android runtime.  We have to do this bit// of nastiness because the Android runtime initialization requires// some of the core system services to already be started.// All other servers should just start the Android runtime at// the beginning of their processes's main(), before calling// the init function.
        ALOGI("System server: starting Android runtime.\n");
        AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    
        ALOGI("System server: starting Android services.\n");
        JNIEnv* env = runtime->getJNIEnv();
        if (env == NULL) {
            return UNKNOWN_ERROR;
        }
        jclass clazz = env->FindClass("com/android/server/SystemServer");
        if (clazz == NULL) {
            return UNKNOWN_ERROR;
        }
        jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
        if (methodId == NULL) {
            return UNKNOWN_ERROR;
        }
        env->CallStaticVoidMethod(clazz, methodId);
    
        ALOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        ALOGI("System server: exiting thread pool.\n");
    
        return NO_ERROR;
    }

    我们可以看到

    SurfaceFlinger::instantiate();
    

    但它本身并没有实现instantiate()方法,那找它的父类。
    /frameworks/native/include/binder/BinderService.h

    namespaceandroid {
    
    template<typename SERVICE>
    classBinderService
    {public:
        static status_t publish(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
        }
    
        static void publishAndJoinThreadPool(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
            ProcessState::self()->startThreadPool();
            IPCThreadState::self()->joinThreadPool();
        }
    
        staticvoid instantiate() { publish(); }
    
        static status_t shutdown() {
            return NO_ERROR;
        }
    };
    
    
    }; // namespace android// ---------------------------------------------------------------------------#endif // ANDROID_BINDER_SERVICE_H

    会调用publish()方法。
    而SERVICE在这里是一个模板类。在这里SERVICE自然对应SurfaceFlinger
    所以publish()会向ServiceManager添加一个Service这个Service就是Surfaceflinger。
    然后我们看SurfaceFlinger的构造函数
    /frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    SurfaceFlinger::SurfaceFlinger()
        :   BnSurfaceComposer(), Thread(false),
            mTransactionFlags(0),
            mTransactionPending(false),
            mAnimTransactionPending(false),
            mLayersRemoved(false),
            mRepaintEverything(0),
            mBootTime(systemTime()),
            mVisibleRegionsDirty(false),
            mHwWorkListDirty(false),
            mDebugRegion(0),
            mDebugDDMS(0),
            mDebugDisableHWC(0),
            mDebugDisableTransformHint(0),
            mDebugInSwapBuffers(0),
            mLastSwapBufferTime(0),
            mDebugInTransaction(0),
            mLastTransactionTime(0),
            mBootFinished(false)
    {
        ALOGI("SurfaceFlinger is starting");
    
        // debugging stuff...charvalue[PROPERTY_VALUE_MAX];
    
        property_get("debug.sf.showupdates", value, "0");
        mDebugRegion = atoi(value);
    
        property_get("debug.sf.ddms", value, "0");
        mDebugDDMS = atoi(value);
        if (mDebugDDMS) {
            if (!startDdmConnection()) {
                // start failed, and DDMS debugging not enabled
                mDebugDDMS = 0;
            }
        }
        ALOGI_IF(mDebugRegion, "showupdates enabled");
        ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
    }

    可还是没有发现run()方法的影踪,没有办法只得去父类构造方法看
    结果发现也没有!!!
    没有办法,继续在源码中搜索SurfaceFlinger,结果发现与之相关的信息大多是sp
    就看看sp吧。
    sp是Android在c++中搞得类似java中弱引用、强引用的一套指针概念,那应该是方便回收吧。
    而Android Framework中的c++世界,RefBase这个类有点像java中的Object.
    而sp是一个模板类。

    总之调用sp时会调用SurfaceFlinger的onFirstRef()方法。
    那好,看代码吧

    void SurfaceFlinger::onFirstRef()
    {
        mEventQueue.init(this);
    
        run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
    
        // Wait for the main thread to be done with its initialization
        mReadyToRunBarrier.wait();
    }

    看见没有?run()方法在这里调用了。

    所以,在Framework中如果你找不到一个Thread在何处被启动,那么去它的onFirstRef()方法中去看看吧

    展开全文
  • Thread 的构造方法

    万次阅读 2014-07-08 19:26:28
    在Java中创建线程有两种方法:使用Thread类和使用Runnable接口。在使用Runnable接口时需要建立一个Thread实例。因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例。Thread类的...

    Java中创建线程有两种方法:使用Thread类和使用Runnable接口。在使用Runnable接口时需要建立一个Thread实例。因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例。Thread类的构造方法被重载了八次,构造方法如下:

    public Thread( );
    public Thread(Runnable target);
    public Thread(String name);
    public Thread(Runnable target, String name);
    public Thread(ThreadGroup group, Runnable target);
    public Thread(ThreadGroup group, String name);
    public Thread(ThreadGroup group, Runnable target, String name);
    public Thread(ThreadGroup group, Runnable target, String name,  long stackSize);

    Runnable target

    实现了Runnable接口的类的实例。要注意的是Thread类也实现了Runnable接口,因此,从Thread类继承的类的实例也可以作为target传入这个构造方法。

    String name

    线程的名子。这个名子可以在建立Thread实例后通过Thread类的setName方法设置。如果不设置线程的名子,线程就使用默认的线程名:Thread-NN是线程建立的顺序,是一个不重复的正整数。

    ThreadGroup group

    当前建立的线程所属的线程组。如果不指定线程组,所有的线程都被加到一个默认的线程组中。关于线程组的细节将在后面的章节详细讨论。

    long stackSize

        线程栈的大小,这个值一般是CPU页面的整数倍。如x86的页面大小是4KB。在x86平台下,默认的线程栈大小是12KB 

    一个普通的Java类只要从Thread类继承,就可以成为一个线程类。并可通过Thread类的start方法来执行线程代码。虽然Thread类的子类可以直接实例化,但在子类中必须要覆盖Thread类的run方法才能真正运行线程的代码。下面的代码给出了一个使用Thread类建立线程的例子:

      001   package mythread;
      002  
      003   public  class Thread1  extends Thread
      004  {
      005       public  void run()
      006      {
      007          System.out.println( this.getName());
      008      }
      009       public  static  void main(String[] args)
      010      {
      011          System.out.println(Thread.currentThread().getName());
      012          Thread1 thread1 =  new Thread1();
      013          Thread1 thread2 =  new Thread1 ();
      014          thread1.start();
      015          thread2.start();
      016      }
      017  }


         上面的代码建立了两个线程:thread1和thread2。上述代码中的005至008行是Thread1类的run方法。当在014和015行调用start方法时,系统会自动调用run方法。在007行使用this.getName()输出了当前线程的名字,由于在建立线程时并未指定线程名,因此,所输出的线程名是系统的默认值,也就是Thread-n的形式。在011行输出了主线程的线程名。
        上面代码的运行结果如下:

    main
    Thread-0
    Thread-1

    从上面的输出结果可以看出,第一行输出的main是主线程的名子。后面的Thread-1Thread-2分别是thread1thread2的输出结果。

    注意:任何一个Java程序都必须有一个主线程。一般这个主线程的名子为main。只有在程序中建立另外的线程,才能算是真正的多线程程序。也就是说,多线程程序必须拥有一个以上的线程。
        Thread类有一个重载构造方法可以设置线程名。除了使用构造方法在建立线程时设置线程名,还可以使用Thread类的setName方法修改线程名。要想通过Thread类的构造方法来设置线程名,必须在Thread的子类中使用Thread类的public Thread(String name)构造方法,因此,必须在Thread的子类中也添加一个用于传入线程名的构造方法。下面的代码给出了一个设置线程名的例子:

      001   package mythread;
      002  
      003   public  class Thread2  extends Thread
      004  {
      005       private String who;
      006  
      007       public  void run()
      008      {
      009          System.out.println(who + ":" +  this.getName());
      010      }
      011       public Thread2(String who)
      012      {
      013           super();
      014           this.who = who;
      015      }
      016       public Thread2(String who, String name)
      017      {
      018           super(name);
      019           this.who = who;
      020      }
      021       public  static  void main(String[] args)
      022      {
      023          Thread2 thread1 =  new Thread2 ("thread1", "MyThread1");
      024          Thread2 thread2 =  new Thread2 ("thread2");
      025          Thread2 thread3 =  new Thread2 ("thread3");
      026          thread2.setName("MyThread2");
      027          thread1.start();
      028          thread2.start();
      029          thread3.start();
      030      }
      031  

    在类中有两个构造方法:

    011行:public sample2_2(String who)

    这个构造方法有一个参数:who。这个参数用来标识当前建立的线程。在这个构造方法中仍然调用Thread的默认构造方法public Thread( )

    016行:public sample2_2(String who, String name)

    这个构造方法中的who和第一个构造方法的who的含义一样,而name参数就是线程的名名。在这个构造方法中调用了Thread类的public Thread(String name)构造方法,也就是第018行的super(name)

    main方法中建立了三个线程:thread1thread2thread3。其中thread1通过构造方法来设置线程名,thread2通过setName方法来修改线程名,thread3未设置线程名。

        运行结果如下: 

    thread1:MyThread1
    thread2:MyThread2
    thread3:Thread-1

    从上面的输出结果可以看出,thread1thread2的线程名都已经修改了,而thread3的线程名仍然为默认值:Thread-1thread3的线程名之所以不是Thread-2,而是Thread-1,这是因为在026已经指定了thread2的Name,因此,启动thread3时就将thread3的线程名设为Thread-1因此就会得到上面的输出结果。

    注意:在调用start方法前后都可以使用setName设置线程名,但在调用start方法后使用setName修改线程名,会产生不确定性,也就是说可能在run方法执行完后才会执行setName。如果在run方法中要使用线程名,就会出现虽然调用了setName方法,但线程名却未修改的现象。

    Thread类的start方法不能多次调用,如不能调用两次thread1.start()方法。否则会抛出一个IllegalThreadStateException异常。

    展开全文
  • 它们普遍的特点就是有一个threadLoop方法。按照字面的意思应该是这个线程能够循环处理数据。对应我想到到了java上层中的HandlerThread,这个估计也差不多,但当时心里总有一个疙瘩,想弄清楚它到底是怎么循环起来的...

    当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了许许多多的Thread。它们普遍的特点就是有一个threadLoop方法。按照字面的意思应该是这个线程能够循环处理数据。对应我想到到了java上层中的HandlerThread,这个估计也差不多,但当时心里总有一个疙瘩,想弄清楚它为什么能够循环,还有它到底是怎么循环起来的?

    Android中java世界的Thread

    我们先来看看java是怎么创建一个线程的。这个是最舒服的,也是我最熟悉的。

    
    new Thread(new Runnable() {
    
            @Override
            public void run() {
                // TODO Auto-generated method stub
                    ...
            }
    }).start();
    

    当然,你也可以在android中创建一个消息循环的HandlerThread

    HandlerThread mThread = new HandlerThread("test");
    mThread.start();
    Handler mHandler = new Handler(mThread.getLooper()){
    
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                super.handleMessage(msg);
            }
    
    };
    

    上面中通过mHandler发送消息就可以在mThread中处理了,并且这个mThread不是UIThread,不会阻塞主线程。
    HandlerThread是一个好东西,在源码中处处可见,希望对此不熟悉的新手及时去学习下它的用法。

    Linux下c语言的Thread

    java世界的Thread很方便,那么c呢?
    Android基于linux所以,多线程编程也应该基于linux下的多线程。linux下的c语言用pthread。大家可以看这篇文章。
    linux下C/C++,多线程pthread

    我把里面的例子改良了一下
    test.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    
    //线程函数
    void *test(void *ptr)
    {
        int i;
        for(i=0;i<8;i++)
        {
            printf("the pthread running ,count: %d\n",i);
            sleep(1); 
        }
    
    }
    
    
    int main(void)
    {
        pthread_t pId;
        int i,ret;
        //创建子线程,线程id为pId
        ret = pthread_create(&pId,NULL,test,NULL);
    
        if(ret != 0)
        {
            printf("create pthread error!\n");
            exit(1);
        }
    
        for(i=0;i < 5;i++)
        {
            printf("main thread running ,count : %d\n",i);
            sleep(1);
        }
    
        printf("main thread will exit when pthread is over\n");
        //等待线程pId的完成
        pthread_join(pId,NULL);
        printf("main thread  exit\n");
    
        return 0;
    
    }

    然后编译

    gcc -o test test.c -lpthread
    ./test

    运行结果如下

    main thread running ,count : 0
    the pthread running ,count: 0
    main thread running ,count : 1
    the pthread running ,count: 1
    main thread running ,count : 2
    the pthread running ,count: 2
    main thread running ,count : 3
    the pthread running ,count: 3
    main thread running ,count : 4
    the pthread running ,count: 4
    main thread will exit when pthread is over
    the pthread running ,count: 5
    the pthread running ,count: 6
    the pthread running ,count: 7
    main thread  exit
    

    例子比较简单,主要是创建一个线程,然后主线程等待子线程运行完毕再退出。

    Android Framework中的Thread

    下面焦点回到文章的主题当中,我们来看看Framework中常用的Thread是个何种形态。
    先看看活生生的例子。
    在源码中搜索threadLoop,当然也可以搜索thread,然后随便挑选一个Thread子类进行研究。这里挑选
    /frameworks/av/services/audioflinger/AudioWatchdog.h

    #ifndef AUDIO_WATCHDOG_H
    #define AUDIO_WATCHDOG_H
    
    #include <time.h>
    #include <utils/Thread.h>
    
    namespace android {
    
    ......
    
    class AudioWatchdog : public Thread {
    
    public:
        AudioWatchdog(unsigned periodMs = 50) : Thread(false /*canCallJava*/), mPaused(false),
                mPeriodNs(periodMs * 1000000), mMaxCycleNs(mPeriodNs * 2),
                // mOldTs
                // mLogTs initialized below
                mOldTsValid(false), mUnderruns(0), mLogs(0), mDump(&mDummyDump)
            {
    #define MIN_TIME_BETWEEN_LOGS_SEC 60
                // force an immediate log on first underrun
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
            }
        virtual         ~AudioWatchdog() { }
    
         // Do not call Thread::requestExitAndWait() without first calling requestExit().
        // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
        virtual void        requestExit();
    
        // FIXME merge API and implementation with AudioTrackThread
        void            pause();        // suspend thread from execution at next loop boundary
        void            resume();       // allow thread to execute, if not requested to exit
    
        // Where to store the dump, or NULL to not update
        void            setDump(AudioWatchdogDump* dump);
    
    private:
        virtual bool    threadLoop();
    
        Mutex           mMyLock;        // Thread::mLock is private
        Condition       mMyCond;        // Thread::mThreadExitedCondition is private
        bool            mPaused;        // whether thread is currently paused
    
        ......
    };
    
    }   // namespace android
    
    #endif  // AUDIO_WATCHDOG_H

    我们可以看到AudioWatchDog确实是Thread的子类,那好,下面看实现。
    /frameworks/av/services/audioflinger/AudioWatchdog.cpp

    #define LOG_TAG "AudioWatchdog"
    //#define LOG_NDEBUG 0
    
    #include <utils/Log.h>
    #include "AudioWatchdog.h"
    
    namespace android {
    
    
    bool AudioWatchdog::threadLoop()
    {
        {
            AutoMutex _l(mMyLock);
            if (mPaused) {
                mMyCond.wait(mMyLock);
                // ignore previous timestamp after resume()
                mOldTsValid = false;
                // force an immediate log on first underrun after resume()
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
                // caller will check for exitPending()
                return true;
            }
        }
        struct timespec newTs;
        int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
        if (rc != 0) {
            pause();
            return false;
        }
        if (!mOldTsValid) {
            mOldTs = newTs;
            mOldTsValid = true;
            return true;
        }
        time_t sec = newTs.tv_sec - mOldTs.tv_sec;
        long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
        if (nsec < 0) {
            --sec;
            nsec += 1000000000;
        }
        mOldTs = newTs;
        // cycleNs is same as sec*1e9 + nsec, but limited to about 4 seconds
        uint32_t cycleNs = nsec;
        if (sec > 0) {
            if (sec < 4) {
                cycleNs += sec * 1000000000;
            } else {
                cycleNs = 4000000000u;
            }
        }
        mLogTs.tv_sec += sec;
        if ((mLogTs.tv_nsec += nsec) >= 1000000000) {
            mLogTs.tv_sec++;
            mLogTs.tv_nsec -= 1000000000;
        }
        if (cycleNs > mMaxCycleNs) {
            mDump->mUnderruns = ++mUnderruns;
            if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) {
                mDump->mLogs = ++mLogs;
                mDump->mMostRecent = time(NULL);
                ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u",
                    mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs);
                mLogTs.tv_sec = 0;
                mLogTs.tv_nsec = 0;
            }
        }
        struct timespec req;
        req.tv_sec = 0;
        req.tv_nsec = mPeriodNs;
        rc = nanosleep(&req, NULL);
        if (!((rc == 0) || (rc == -1 && errno == EINTR))) {
            pause();
            return false;
        }
        return true;
    }
    
    void AudioWatchdog::requestExit()
    {
        // must be in this order to avoid a race condition
        Thread::requestExit();
        resume();
    }
    
    void AudioWatchdog::pause()
    {
        AutoMutex _l(mMyLock);
        mPaused = true;
    }
    
    void AudioWatchdog::resume()
    {
        AutoMutex _l(mMyLock);
        if (mPaused) {
            mPaused = false;
            mMyCond.signal();
        }
    }
    
    }   // namespace android

    很明显,它的核心方法就是threadLoop(),在本文中我们不关心它具体的功能,只想确定它是怎么启动的呢?又是怎么循环运行的呢?带着疑问我又在源码中搜索关键字AudioWatchdog
    结果发现有两个地方引用了。

    /frameworks/av/services/audioflinger/AudioFlinger.h
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    在AudioFlinger.h中MixerThread中有个AudioWatchdog的sp对象

    
     class MixerThread : public PlaybackThread {
        public:
            MixerThread (const sp<AudioFlinger>& audioFlinger,
                         AudioStreamOut* output,
                         audio_io_handle_t id,
                         audio_devices_t device,
                         type_t type = MIXER);
            virtual             ~MixerThread();
    
    
    
    
    
        protected:
    
    
                        AudioMixer* mAudioMixer;    // normal mixer
        private:
    
                        sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread
    
    
        };
    

    我们再看代码
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
            audio_io_handle_t id, audio_devices_t device, type_t type)
        :   PlaybackThread(audioFlinger, output, id, device, type),
            // mAudioMixer below
            // mFastMixer below
            mFastMixerFutex(0)
            // mOutputSink below
            // mPipeSink below
            // mNormalSink below
    {
    
    ......
    #ifdef AUDIO_WATCHDOG
            // create and start the watchdog
            mAudioWatchdog = new AudioWatchdog();
            mAudioWatchdog->setDump(&mAudioWatchdogDump);
            //AudioWatchdog的run方法在此调用,所以线程启动
            mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
            tid = mAudioWatchdog->getTid();
            err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
            if (err != 0) {
                ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                        kPriorityFastMixer, getpid_cached, tid, err);
            }
    #endif
    
    ......
    }

    删掉不相关代码,我们看到AudioWatchdog对象确实创建了,并且调用了它的run方法。在java中Thread的run方法就是启动,这个也应该如此。但是如之前的源码所示AudioWatchdog.cpp中并没有实现run方法,怎么办呢?别紧张,它还有父类Thread.

    /frameworks/native/include/utils/Thread.h

    
    #ifndef _LIBS_UTILS_THREAD_H
    #define _LIBS_UTILS_THREAD_H
    
    #include <stdint.h>
    #include <sys/types.h>
    #include <time.h>
    
    #if defined(HAVE_PTHREADS)
    # include <pthread.h>
    #endif
    
    #include <utils/Condition.h>
    #include <utils/Errors.h>
    #include <utils/Mutex.h>
    #include <utils/RefBase.h>
    #include <utils/Timers.h>
    #include <utils/ThreadDefs.h>
    
    // ---------------------------------------------------------------------------
    namespace android {
    // ---------------------------------------------------------------------------
    
    class Thread : virtual public RefBase
    {
    public:
        // Create a Thread object, but doesn't create or start the associated
        // thread. See the run() method.
                            Thread(bool canCallJava = true);
        virtual             ~Thread();
    
        // Start the thread in threadLoop() which needs to be implemented.
        virtual status_t    run(    const char* name = 0,
                                    int32_t priority = PRIORITY_DEFAULT,
                                    size_t stack = 0);
    
        // Ask this object's thread to exit. This function is asynchronous, when the
        // function returns the thread might still be running. Of course, this
        // function can be called from a different thread.
        virtual void        requestExit();
    
        // Good place to do one-time initializations
        virtual status_t    readyToRun();
    
        // Call requestExit() and wait until this object's thread exits.
        // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
        // this function from this object's thread. Will return WOULD_BLOCK in
        // that case.
                status_t    requestExitAndWait();
    
        // Wait until this object's thread exits. Returns immediately if not yet running.
        // Do not call from this object's thread; will return WOULD_BLOCK in that case.
                status_t    join();
    
    #ifdef HAVE_ANDROID_OS
        // Return the thread's kernel ID, same as the thread itself calling gettid() or
        // androidGetTid(), or -1 if the thread is not running.
                pid_t       getTid() const;
    #endif
    
    protected:
        // exitPending() returns true if requestExit() has been called.
                bool        exitPending() const;
    
    private:
        // Derived class must implement threadLoop(). The thread starts its life
        // here. There are two ways of using the Thread object:
        // 1) loop: if threadLoop() returns true, it will be called again if
        //          requestExit() wasn't called.
        // 2) once: if threadLoop() returns false, the thread will exit upon return.
        virtual bool        threadLoop() = 0;
    
    private:
        Thread& operator=(const Thread&);
        static  int             _threadLoop(void* user);
        const   bool            mCanCallJava;
        // always hold mLock when reading or writing
                thread_id_t     mThread;
        mutable Mutex           mLock;
                Condition       mThreadExitedCondition;
                status_t        mStatus;
        // note that all accesses of mExitPending and mRunning need to hold mLock
        volatile bool           mExitPending;
        volatile bool           mRunning;
                sp<Thread>      mHoldSelf;
    #ifdef HAVE_ANDROID_OS
        // legacy for debugging, not used by getTid() as it is set by the child thread
        // and so is not initialized until the child reaches that point
                pid_t           mTid;
    #endif
    };
    
    
    }; // namespace android
    
    // ---------------------------------------------------------------------------
    #endif // _LIBS_UTILS_THREAD_H
    // 

    可以看到确实有run方法。那下面看看它的实现

    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
        Mutex::Autolock _l(mLock);
    
        if (mRunning) {
            // thread already started
            return INVALID_OPERATION;
        }
    
        // reset status and exitPending to their default value, so we can
        // try again after an error happened (either below, or in readyToRun())
        mStatus = NO_ERROR;
        mExitPending = false;
        mThread = thread_id_t(-1);
    
        // hold a strong reference on ourself
        mHoldSelf = this;
    
        mRunning = true;
    
        bool res;
        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;   // something happened!
            mRunning = false;
            mThread = thread_id_t(-1);
            mHoldSelf.clear();  // "this" may have gone away after this.
    
            return UNKNOWN_ERROR;
        }
    
        // Do not refer to mStatus here: The thread is already running (may, in fact
        // already have exited with a valid mStatus result). The NO_ERROR indication
        // here merely indicates successfully starting the thread and does not
        // imply successful termination/execution.
        return NO_ERROR;
    
        // Exiting scope of mLock is a memory barrier and allows new thread to run
    }
    
    

    run()方法中有这么一段

    if (mCanCallJava) {
            res = createThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        } else {
            res = androidCreateRawThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        }

    mCanCallJava的意思是能不能被JNI层调用,然后根据值去创建Thread,这里有两个分支,我们就选择createThreadEtc()
    最终代码会走到这里

    int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                                   void *userData,
                                   const char* threadName,
                                   int32_t threadPriority,
                                   size_t threadStackSize,
                                   android_thread_id_t *threadId)
    {
        ......
            entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
            userData = t;
        }
    #endif
    
        if (threadStackSize) {
            pthread_attr_setstacksize(&attr, threadStackSize);
        }
    
        errno = 0;
        pthread_t thread;
        //在此创建,文章开头我有写例子怎么用c语言创建一个线程
        int result = pthread_create(&thread, &attr,
                        (android_pthread_entry)entryFunction, userData);
        pthread_attr_destroy(&attr);
        if (result != 0) {
            ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
                 "(android threadPriority=%d)",
                entryFunction, result, errno, threadPriority);
            return 0;
        }
    
        ......
        return 1;
    }

    删除了不相关代码,大家看看是不是很熟悉啊。我在文章开始的部分就写出了linux下c语言pthread创建线程的例子,大家可以回头看看。也就是pthread_create()。这里面传进来的entryFunction是Thread中的_threadLoop()

    int Thread::_threadLoop(void* user)
    {
        Thread* const self = static_cast<Thread*>(user);
    
        sp<Thread> strong(self->mHoldSelf);
        wp<Thread> weak(strong);
        self->mHoldSelf.clear();
    
    #ifdef HAVE_ANDROID_OS
        // this is very useful for debugging with gdb
        self->mTid = gettid();
    #endif
    
        bool first = true;
    
        do {
            bool result;
            if (first) {
                first = false;
                self->mStatus = self->readyToRun();
                result = (self->mStatus == NO_ERROR);
    
                if (result && !self->exitPending()) {
                    // Binder threads (and maybe others) rely on threadLoop
                    // running at least once after a successful ::readyToRun()
                    // (unless, of course, the thread has already been asked to exit
                    // at that point).
                    // This is because threads are essentially used like this:
                    //   (new ThreadSubclass())->run();
                    // The caller therefore does not retain a strong reference to
                    // the thread and the thread would simply disappear after the
                    // successful ::readyToRun() call instead of entering the
                    // threadLoop at least once.
                    //调用threadLoop()
                    result = self->threadLoop();
                }
            } else {
                result = self->threadLoop();
            }
    
            // establish a scope for mLock
            {
            Mutex::Autolock _l(self->mLock);
            if (result == false || self->mExitPending) {
                self->mExitPending = true;
                self->mRunning = false;
                // clear thread ID so that requestExitAndWait() does not exit if
                // called by a new thread using the same thread ID as this one.
                self->mThread = thread_id_t(-1);
                // note that interested observers blocked in requestExitAndWait are
                // awoken by broadcast, but blocked on mLock until break exits scope
                self->mThreadExitedCondition.broadcast();
                break;
            }
            }
    
            // Release our strong reference, to let a chance to the thread
            // to die a peaceful death.
            strong.clear();
            // And immediately, re-acquire a strong reference for the next loop
            strong = weak.promote();
        } while(strong != 0);
    
        return 0;
    }

    _threadLoop()这个方法就是Thread的最大秘密,它是一个while循环。

    1、创建线程时,会sp和wp一次线程本身。
    2、如果是第一次执行会运行线程的readyToRun()方法,再执行threadLoop(),否则,直接运行threadLoop()。
    3、threadLoop()方法有返回值,如果threadLoop()返回false的时候,线程会做清理工作,然后退出while循环,结束运行。

    所以在这里,我开始时的疑问—为什么线程Thread中的threadLoop()能够循环处理数据就到此做了说明。
    Thread被创建,
    Thread中的run被调用,
    __threadLoop()被调用,
    readyToRun()被调用,
    然后循环调用threadLoop()。
    并且在threadLoop()返回false时,可以退出循环。

    !!!
    !!!
    还有,最关键的一点是threadLoop能够循环其实是因为调用它的_threadLoop()方法里面有一个while循环

    特殊情况

    有的时候Android Framework中Thread的run()方法很难发现在哪里被调用。如SurfaceFlinger它也是一个Thread子类。在源码中搜索可以发现它的创建位置

    class SurfaceFlinger : public BinderService<SurfaceFlinger>,
                           public BnSurfaceComposer,
                           private IBinder::DeathRecipient,
                           private Thread,
                           private HWComposer::EventHandler
    {
    public:
        static char const* getServiceName() {
            return "SurfaceFlinger";
        }
    
        SurfaceFlinger();
    
    
        /* ------------------------------------------------------------------------
         * Thread interface
         */
        virtual bool threadLoop();
        virtual status_t readyToRun();
        virtual void onFirstRef();
    
    
    };
    
    // ---------------------------------------------------------------------------
    }; // namespace android
    
    #endif // ANDROID_SURFACE_FLINGER_H

    去找它创建的地方
    /frameworks/base/cmds/system_server/library/system_init.cpp

    extern "C" status_t system_init()
    {
        ALOGI("Entered system_init()");
    
        sp<ProcessState> proc(ProcessState::self());
    
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p\n", sm.get());
    
    
    
        char propBuf[PROPERTY_VALUE_MAX];
        property_get("system_init.startsurfaceflinger", propBuf, "1");
        if (strcmp(propBuf, "1") == 0) {
            // Start the SurfaceFlinger
            SurfaceFlinger::instantiate();
        }
    
    
        // And now start the Android runtime.  We have to do this bit
        // of nastiness because the Android runtime initialization requires
        // some of the core system services to already be started.
        // All other servers should just start the Android runtime at
        // the beginning of their processes's main(), before calling
        // the init function.
        ALOGI("System server: starting Android runtime.\n");
        AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    
        ALOGI("System server: starting Android services.\n");
        JNIEnv* env = runtime->getJNIEnv();
        if (env == NULL) {
            return UNKNOWN_ERROR;
        }
        jclass clazz = env->FindClass("com/android/server/SystemServer");
        if (clazz == NULL) {
            return UNKNOWN_ERROR;
        }
        jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
        if (methodId == NULL) {
            return UNKNOWN_ERROR;
        }
        env->CallStaticVoidMethod(clazz, methodId);
    
        ALOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        ALOGI("System server: exiting thread pool.\n");
    
        return NO_ERROR;
    }

    我们可以看到

     SurfaceFlinger::instantiate();

    但它本身并没有实现instantiate()方法,那之类找它的父类了。
    /frameworks/native/include/binder/BinderService.h

    namespace android {
    
    template<typename SERVICE>
    class BinderService
    {
    public:
        static status_t publish(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
        }
    
        static void publishAndJoinThreadPool(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
            ProcessState::self()->startThreadPool();
            IPCThreadState::self()->joinThreadPool();
        }
    
        static void instantiate() { publish(); }
    
        static status_t shutdown() {
            return NO_ERROR;
        }
    };
    
    
    }; // namespace android
    // ---------------------------------------------------------------------------
    #endif // ANDROID_BINDER_SERVICE_H

    会调用publish()方法。
    而SERVICE在这里是一个模板类。在这里SERVICE自然对应SurfaceFlinger
    所以publish()会向ServiceManager添加一个Service这个Service就是Surfaceflinger。

    然后我们看SurfaceFlinger的构造函数
    /frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    SurfaceFlinger::SurfaceFlinger()
        :   BnSurfaceComposer(), Thread(false),
            mTransactionFlags(0),
            mTransactionPending(false),
            mAnimTransactionPending(false),
            mLayersRemoved(false),
            mRepaintEverything(0),
            mBootTime(systemTime()),
            mVisibleRegionsDirty(false),
            mHwWorkListDirty(false),
            mDebugRegion(0),
            mDebugDDMS(0),
            mDebugDisableHWC(0),
            mDebugDisableTransformHint(0),
            mDebugInSwapBuffers(0),
            mLastSwapBufferTime(0),
            mDebugInTransaction(0),
            mLastTransactionTime(0),
            mBootFinished(false)
    {
        ALOGI("SurfaceFlinger is starting");
    
        // debugging stuff...
        char value[PROPERTY_VALUE_MAX];
    
        property_get("debug.sf.showupdates", value, "0");
        mDebugRegion = atoi(value);
    
        property_get("debug.sf.ddms", value, "0");
        mDebugDDMS = atoi(value);
        if (mDebugDDMS) {
            if (!startDdmConnection()) {
                // start failed, and DDMS debugging not enabled
                mDebugDDMS = 0;
            }
        }
        ALOGI_IF(mDebugRegion, "showupdates enabled");
        ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
    }

    但是遗憾的是没有发现run()方法的影踪,没有办法只得去父类构造方法看
    结果发现也没有!!!

    没有办法,继续在源码中搜索SurfaceFlinger,结果发现与之相关的信息大多是sp<SurfaceFlinger>
    就看看sp吧。
    sp是Android在c++中搞得类似java中弱引用、强引用的一套指针概念,那应该是方便回收吧。
    而Android Framework中的c++世界,RefBase这个类有点像java中的Object.
    而sp是一个模板类。这部分内容,请看点击下面链接

    Android中的sp和wp指针

    上面的链接讲得还算详细。这里纠结sp的过多细节,长话短说,总之第一次对SurfaceFlinger引用调用sp<SurfaceFlinger>时会调用SurfaceFlinger的onFirstRef()方法。
    那好,看代码吧

    void SurfaceFlinger::onFirstRef()
    {
        mEventQueue.init(this);
        //run方法在此被调用
        run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
    
        // Wait for the main thread to be done with its initialization
        mReadyToRunBarrier.wait();
    }

    看见没有?run()方法在这里调用了。

    所以,在Framework中如果你找不到一个Thread在何处被启动,那么去它的onFirstRef()方法中去看看吧

    展开全文
  • 为什么wait,notify,notifyAll声明在类Object中而不是Thread中这个问题是一个非常有名的java核心面试题,在各种级别的Java开发者面试中都会出现

    多线程概述

    Java是一个支持多线程的开发语言,多线程并发执行任务可以充分利用CPU资源,提高多任务并发执行效率(注意区分:多线程并不会加快任务的执行速度,而是可以充分利用多核CPU让线程轮流进行工作,达到了一种“同时”工作的效果)。

    并发时的产生问题

    多线程在执行时,会遇到一些问题,问题的关键原因则是在共享资源的更新操作上容易产生冲突。

    解决的方向

    解决冲突的方式则是从共享资源的占用机制入手,保证共享资源同一时刻只能被一个线程占用,从而达到数据一致。

    具体实现方式中的一种

    在Java中提供了synchorinzed关键字,在该关键字修饰的代码内,称为同步代码块,线程执行该区域代码需要获取锁,在获取成功之后,其他线程需要等该线程执行完毕释放锁之后才能获取到。

    wait、notify、notifyAll方法的作用

    在同步代码块中,可以使用wait、notify来控制当前占用资源的线程进入阻塞队列与唤醒进入就绪队列
    也就是说,上述两个方法实际上实现的时线程之间的通信机制,用来通知线程的阻塞与唤醒。

    引出问题:为什么定义在Object中而不是Thread类

    线程为了进入临界区(也就是同步块内),需要获得锁并等待锁可用,它们并不知道也不需要知道哪些线程持有锁,它们只需要知道当前资源是否被占用,是否可以获得锁,所以锁的持有状态应该由同步监视器来获取,而不是线程本身。

    一个比喻

    形象的比喻:一个女孩子同时被10个男孩子追,在同一个时间段内只能陪一个男孩子看电影,当其中一个男孩想要邀请女孩看电影时,应该由女孩子来通知男孩子,这个时间段可不可以赴约,而不应该是男孩子询问其他情敌抑或是由情敌之间相互通知谁该去赴约(那还不打起来了)。
    例子中女孩相当于”共享资源“(每一个男孩机会均等),在Java中是一个对象,男孩子们相当于线程,多个线程之间的通信机制,由共享资源(就是前文所说的同步监视器)来实现,即将wait、notify、notifyAll方法定义在Object中是最合理的

    较详细的解释

    以下是一篇英文博客的翻译:
    为什么它们不应该在Thread类,(我)的一些想法是:

    1. wait和nofity不是常见的普通java方法或同步工具,在Java中它们更多的是实现两个线程之间的通信机制。
      如果不能通过类似synchronized这样的Java关键字来实现这种机制,那么Object类中就是定义它们最好的地方,以此来使任何Java对象都可以拥有实现线程通信机制的能力。
      记住synchronized和wait,notify是两个不同的问题域,并且不要混淆它们的相似或相关性。 同步类似竞态条件,是提供线程间互斥和确保Java类的线程安全性的,而wait和notify是两个线程之间的通信机制。

    2. 另一个原因:每个对象都可以作为锁

    3. 在Java中,为了进入临界区代码段,线程需要获得锁并且它们等待锁可用,它们不知道哪些线程持有锁而它们只知道锁是由某个线程保持,它们应该等待锁而不是知道哪个线程在同步块内并要求它们释放锁。 这个比喻适合等待和通知在object类而不是Java中的线程。

    这些只是我的想法为什么wait和notify方法在Object类中声明,而不是Java中的Thread,当然你可以有不同的观点。

    在现实中,它就是Java不支持操作符重载一样,只是Java设计者做的一个设计决定。 无论如何,如果你有任何其它令人信服的理由请发布出来。

    还有一点需要注意:wait、notify、notifyAll方法只能在同步代码块中使用,在非同步代码块中会导致异常

    因为只有在同步代码块中才会涉及到锁的概念,在非并发环境下尝试操作锁会导致失败。

    展开全文
  • Thread之sleep方法

    万次阅读 多人点赞 2017-12-03 10:14:23
    为什么要用sleep,主要是为了暂停当前线程,把cpu片段让出给其他线程,减缓当前线程的执行。 方法的定义: public static void sleep(long millis);...通过定义可以看出sleep方法是本地方法,通过系统调用暂停
  • 每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。 在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡...
  • Thread类的几种常用方法

    万次阅读 2018-08-27 16:45:00
    2.run 此run非彼run (不是在run方法实现线程的逻辑,而是thread.run(),这个run方法是直接调用了线程中的run) 3.yield(暂停当前线程,并执行其他线程) 4.sleep(使当前线程由运行状态变成阻塞状态,若睡眠时...
  • Thread 的join方法解释

    万次阅读 2018-09-03 12:39:50
     Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。具体看代码:   public class JoinTest { public static void main(String [] args) throws InterruptedException { ...
  • android-Thread的run方法和start方法

    千次阅读 2015-05-14 08:43:30
    解说的很精辟,学习一下:Thread的run方法和start方法 1 线程的概念:线程的起动并不是简单的调用了RUN方法,而是由一个线程调度器来分别调用所有线程的RUN方法, 我们普通的RUN方法如果没有执行完是不会...
  • Thread.Abort方法的误区

    千次阅读 2016-12-26 10:58:21
    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Thread.Abort方法后线程就立刻停止了吗...
  • Java Thread之Sleep()使用方法总结

    万次阅读 2018-11-12 17:19:45
    Thread.sleep()是Thread类的一个静态方法,使当前线程休眠,进入阻塞状态(暂停执行),如果线程在睡眠状态被中断,将会抛出IterruptedException中断异常。。主要方法如下: 【a】sleep(long millis) 线程睡眠 ...
  • Thread的Sleep方法详解,

    万次阅读 2018-06-19 14:14:03
    /* 1.Thread.sleep(毫秒) 2.sleep方法是一个静态方法 3.该方法的作用:阻塞该线程,让给其他线程*/public class fuck4 { public static void main(String[] args) throws InterruptedException{ Thread t1=new ...
  • new Thread(new Runnable() { @Override public void run() { System.out.println("Run of Runnable"); } }) { public void run() { System.out.println("Run of Thread"); } }.start(); 执行上述
  • Java中Thread类的方法简介

    万次阅读 2018-06-05 17:37:48
    Thread t1 = new Thread(); t1.start(); 新建线程,应该调用start()方法启动线程;如果直接调用run()方法,该方法也会执行,但会被当做一个普通的方法,在当前线程中顺序执行;而如果使用start()方法,则会创建一个...
  • java Thread的start和run方法的区别

    千次阅读 多人点赞 2019-02-23 20:10:07
    一、认识Thread的 start() 和 run() 概述: t.start()会导致run()方法被调用,run()方法中的内容称为线程体,它就是这个线程需要执行的工作。 用start()来启动线程,实现了真正意义上的启动线程,此时会出现异步...
  • ❤️‍大家好,我是贾斯汀,今天主要聊一聊关于线程的瓜!❤️‍ 先来看一下线程这张图线程的几种运行状态之间运行流程: 看不懂没关系,慢慢来学习,往下学习来继续了解一下~ ... * 创建Thread线
  • RT-Thread Env工具的使用方法

    万次阅读 2017-12-27 21:29:39
    RT-Thread Env工具包括配置器和包管理器,用来对内核和组件的功能进行配置,对组件进行自由裁剪,对线上软件包进行管理,使得系统以搭积木的方式进行构建,简单方便。 简单的解释一下,从RT-Thread的软件结构来看,...
  • 1. Thread类中的常用方法简介 2. Join()方法 3. Sleep() 方法:不会释放锁 4. Yield()方法:线程让步 不会释放锁 1. Thread类中的常用方法简介 首先,先看一下Thread类中的常见方法: 最主要的是区分其中...
  • 为什么不鼓励使用 Thread.stop? 因为它本质上就是不安全的。停止线程会导致解锁它已锁定的所有监视程序(ThreadDeath 异常传播到栈上后即解锁监视程序)。如果这些监视程序前面
  • android 停止 终止 Thread 线程的三种方法
  • Thread.interrupt()方法理解

    千次阅读 2017-07-27 23:07:45
    原博客地址: 多线程编程 实战篇 (四)不客气地说,至少有一半人认为,线程的”中断”就是让线程停止. 如果你也这么认为,那你对多线程...不但不是 让线程停止运行,反而是继续执行线程的手段.对于执行一般逻辑的线程,如
  • Thread.sleep()方法

    万次阅读 2018-03-15 11:14:23
    第二种方式效率要低一些,因为多了一次函数调用,而且通过对象调用静态方法也不太符合“静态”的定义(静态成员最好通过类名直接访问),但功能上是一致的。当需要调用非静态方法时使用第二种方式,否则直接使用第一...
  • Thread

    千次阅读 2015-07-12 22:57:05
    Thread
  • Java中Thread类的start()方法和run()方法

    千次阅读 2017-07-05 18:29:17
    我们知道在Java中可以通过继承一个Thread类来实现一个线程类,继承以后,需要重载run()方法,但是在启动线程的时候则又是用start()方法,这个是几个意思,启动直接用run()不行么,我们试一下。首先还是用start()方法...
  • java中Thread方法介绍

    千次阅读 2016-11-29 17:13:05
    方法摘要  static int activeCount()   返回当前线程的线程组中活动线程的数目。   void checkAccess()   判定当前运行的线程是否有权修改该线程。   int countStackFrames()   已过时。 该调用的...
  • __thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。  ...
  • 1.wait和notify不仅仅是普通方法或同步工具,更重要的是它们是Java中两个线程之间的通信机制 。对语言设计者而言,如果不能通过Java关键字(例如synchronized)实现此通信机制,同时又要确保这个机...
  • 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;...一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法
  • sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程会回到就绪状态)。...
  •  1,这两个方法来自不同的类分别是Thread和Object  2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。  3,wait,notify和notifyAll只能在同步控制方法或者...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 463,613
精华内容 185,445
关键字:

哪个不是thread的方法