Handler 消息机制之扩展(二)

一、HandlerThread

一般想要在子线程中使用Handler,那么需要继承 Thread 类或者new Thread 对象,然后在 run() 调用Looper.prepare() 和 Looper.loop()。现在 HandlerThread 帮我们实现封装好了,省去这些麻烦的步骤,直接使用。

HandlerThread 是 Android 封装好的轻量级异步类,内部通过继承 Thread 和封装 Handler,从而使得创建新线程和其他线程进行通信更加方便。

作用:实现多线程;异步通信,消息传递。

优点:方便实现异步通信。

源码分析:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    ...

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    ...

    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }
    ...

    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;
    }
    ...
}

HandlerThread.java 文件只有 100 多行,非常的简洁。它继承了 Thread 类,那么是需要调用start() ,在 run() 中调用了 Looper.prepare(),为当前线程关联了 Looper。

getLooper():当调用此方法时,线程必须是存活状态,那么意味着其中一个条件:必须先调用 start(),后调用 getLooper()。而且如果mLooper为null,会 wait() 使当前线程等待,释放当前线程共享对象的锁,直到调用 notifyAll() 唤醒线程,继续往下执行。

quit():退出循环,但是也会终止执行中的任务,这样是不安全的。

quitSafely():当执行中的任务执行完成后,才退出循环。

二、Message.Obtain()

public final class Message implements Parcelable {
    ...
    public static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
    ...

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    ...

    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
    ...
}

sPool 是 Message 类型,用来缓存 Message 对象,最多缓存 50 个对象。

在 Looper.loop() 中,handler 处理完 msg 会调用 msg.recycleUnchecked()。recycleUnchecked() 方法里面将用完的 msg 增加到缓存池。

优点:重复利用 Message 对象,减少每次都去堆内存开辟空间的时间,减少JVM垃圾回收,提高效率。

三、ThreadLocal

ThreadLocal 是解决并发的另外一种方案,不使用加锁同步就能解决线程不安全问题。

详细见另一篇文章:Java并发之ThreadLocal_如若、然的专栏-优快云博客

四、Linux 的 epoll+pipe 机制

待完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值