• HandlerThread


    参考: https://github.com/LRH1993/android_interview/blob/master/android/basis/HandlerThread.md

    一、概述

    HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它不仅建立了一个线程,并且创立了消息队列,有自己的looper,可以让我们在自己的线程中分发和处理消息,并对外提供自己这个Looper对象的get方法。

    HandlerThread自带Looper使他可以通过消息队列,来重复使用当前线程,节省系统资源开销。这是它的优点也是缺点,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

    二、HandlerThread的使用

    1.使用步骤

    (1)创建HandlerThread的实例对象

    private HandlerThread handlerThread;
    handlerThread = new HandlerThread("stud");

    该参数表示线程的名字,可以随便选择。

    (2)启动我们创建的HandlerThread线程

    handlerThread.start();

    (3)将我们的handlerThread与Handler绑定在一起。 还记得是怎样将Handler与线程对象绑定在一起的吗?其实很简单,就是将线程的looper与Handler绑定在一起,代码如下:

    threadHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
                @Override
                public boolean handleMessage(Message msg) {
                    checkForUpdate();
                    if (isUpdate) {
                        threadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                    }
                    return true;//返回true不走handler的handlemessage方法
                }
            }) {
                @Override
                public void handleMessage(Message msg) {
                    Log.d("handlerThreadActivity", handlerThread.getName() + "");
                }
            };

    完整代码如下:

    public class HandlerThreadActivity extends Activity {
        private static final int MSG_UPDATE_INFO = 0x100;
        private Handler mMainHandler = new Handler();
        private TextView textView;
        private Button button;
        private Handler threadHandler;
        private HandlerThread handlerThread;
        private boolean isUpdate = false;
        Message message = new Message();
    
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_btn);
            textView = (TextView) findViewById(R.id.tv_task);
            button = (Button) findViewById(R.id.btn_task);
            initHandlerThread();
        }
    
        private void initHandlerThread() {
            handlerThread = new HandlerThread("stud");
            handlerThread.start();
            threadHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
                @Override
                public boolean handleMessage(Message msg) {
                    checkForUpdate();
                    if (isUpdate) {
                        threadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                    }
                    return true;
                }
            }) {
                @Override
                public void handleMessage(Message msg) {
                    Log.d("handlerThreadActivity", handlerThread.getName() + "");
                }
            };
    
            button.setOnClickListener(v -> {
                if (!isUpdate) {                threadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                } else {
                    threadHandler.removeMessages(MSG_UPDATE_INFO);
                }
                isUpdate = !isUpdate;
            });
    
            message.what = MSG_UPDATE_INFO;
        }
    
        //模拟服务器解析数据
        private void checkForUpdate() {
            try {
                Thread.sleep(200);
                mMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        String result = "实时更新中,当前股票行情:<font color='red'>%d</font>";
                        result = String.format(result, (int) (Math.random() * 5000 + 1000));
                        textView.setText(Html.fromHtml(result));
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            handlerThread.quit();
            mMainHandler.removeCallbacksAndMessages(null);
        }
    
        public static void start(Context context) {
            Intent intent = new Intent(context, HandlerThreadActivity.class);
            context.startActivity(intent);
        }
    }

    三、HandlerThread原理:

    HandlerThread的实现原理比较简单,源码也比较少(只有150行代码);

    /**
     * Handy class for starting a new thread that has a looper. The looper can then be 
     * used to create handler classes. Note that start() must still be called.
     */
    public class HandlerThread extends Thread {
        int mPriority;
        int mTid = -1;
        Looper mLooper;
    
        public HandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
        
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
        
        /**
         * Call back method that can be explicitly overridden if needed to execute some
         * setup before Looper loops.
         */
        protected void onLooperPrepared() {
        }
    
        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            //持有锁机制来获得当前线程的Looper对象
            synchronized (this) {
                mLooper = Looper.myLooper();
                //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
                notifyAll();
            }
            //设置线程的优先级别
            Process.setThreadPriority(mPriority);
            //这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前的准备,方便扩展
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }
        
        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
            // 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功,阻塞
            // If the thread has been started, wait until the looper has been created.
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    
        public boolean quit() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quit();
                return true;
            }
            return false;
        }
    
        public boolean quitSafely() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quitSafely();
                return true;
            }
            return false;
        }
    
        /**
         * Returns the identifier of this thread. See Process.myTid().
         */
        public int getThreadId() {
            return mTid;
        }
    }

    我们来逐一解读:

    public class HandlerThread extends Thread {
    (1)它完全可以当一个线程来使用,就像上面我们说的:new HandlerTread().start()这样,但是在子线程中创建一个Handler,需要手动创建Looper,即先Looper.parpare(),完了再Looper.loop()
    这样(参考handler原理解析),我们来看看HandlerThread中的构造方法
        public HandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
        
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
        

    有两个构造方法,一个参数的和两个参数的,name代表当前线程的名称,priority为线程的优先级别

    (2)接着我们看下run方法

     @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            //持有锁机制来获得当前线程的Looper对象
            synchronized (this) {
                mLooper = Looper.myLooper();
                //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
                notifyAll();
            }
            //设置线程的优先级别
            Process.setThreadPriority(mPriority);
            //这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前的准备,方便扩展
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }

    使用HandlerThread的时候必须调用start()方法,接着才可以将我们的HandlerThread和我们的handler绑定在一起,是因为我们是在run()方法才开始初始化我们的looper,而我们调用HandlerThread的start()方法的时候,线程会交给虚拟机调度,由虚拟机自动调用run方法:

    handlerThread.start();
            threadHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
                @Override
                public boolean handleMessage(Message msg) {
                    checkForUpdate();
                    if (isUpdate) {
                        threadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                    }
                    return true;
                }
            })....................

    这里我们为什么要使用锁机制和notifyAll();,原因我们可以从getLooper()方法中知道

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        // 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功,阻塞
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。

    (3)接着我们来看一下quit方法和quitSafe方法

    //调用这个方法退出Looper消息循环,及退出线程
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    //调用这个方法安全地退出线程
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    跟踪这两个方法容易知道只两个方法最终都会调用MessageQueue的quit(boolean safe)方法

    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;
            //安全退出调用这个方法
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {//不安全退出调用这个方法
                removeAllMessagesLocked();
            }
            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

    不安全的会调用removeAllMessagesLocked();这个方法,我们来看这个方法是怎样处理的,其实就是遍历Message链表,移除所有信息的回调,并重置为null。

    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

    安全地会调用removeAllFutureMessagesLocked();这个方法,它会根据Message.when这个属性,判断我们当前消息队列是否正在处理消息,没有正在处理消息的话,直接移除所有回调,正在处理的话,等待该消息处理处理完毕再退出该循环。因此说quitSafe()是安全的,而quit()方法是不安全的,因为quit方法不管是否正在处理消息,直接移除所有回调。

    private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            //判断当前队列中的消息是否正在处理这个消息,没有的话,直接移除所有回调
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {//正在处理的话,等待该消息处理处理完毕再退出该循环
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }
  • 相关阅读:
    优化-IO
    优化-cpu
    优化-内存
    系统优化
    snort -- 入侵检测系统
    tripwire--入侵检测系统
    sudo
    selinux
    pptpd
    C++ 内联函数
  • 原文地址:https://www.cnblogs.com/ivoo/p/10761205.html
Copyright © 2020-2023  润新知