(本文由言念小文原创,转载请注明出处)

一  前言
有Android开发经验的同学都清楚,UI的更新必须在主线程中进行,且主线程不能被阻塞,否则系统ANR异常。我们往往做一些数据处理是耗时操作,必须要在子线程中进行,然后再将处理后的数据切换到主线程去更新UI,这便是线程切换。
线程切换的本质是“数据的切换”,即将数据从一个线程传递到另一个线程。

二  案例描述
老风格,先给出场景案例,然后通过线程切换实现该案例。
案例:在线程A中调用api发送一段数据data,data最终通过线程切换由线程B执行数据处理动作。

三  线程切换基本原理
所谓线程切换,本质就是“数据在线程间切换”,即将一个线程A中的数据,传递到另一个线程B执行数据处理操作。基于以上认知,比较自然的实现逻就是:将线程A中的数据进行拷贝,线程B获取到拷贝数据,然后进行处理,如下图所示。

Java线程切换(一)-LMLPHP

四 案例实现代码


首先创建一个DataHandler类,该类中定义了数据拷贝方法和数据处理线程。在DataHandler中定义了一个用于数据副本存放的成员变量mData;外部模块可通过sendData()将数据拷贝到DataHandler中;在DataHandler构造中初始化数据处理线程(线程B);该线程重写的run()方法中用一个while循环不停查询数据副本mData的值,当检测到mData有数据时,则执行数据处理动作,数据处理完成后,将数副本mData清空。这样便实现了将其他外部线程中的数据切换到线程B中处理。

public class DataHandler {

    // 数据副本
    private String mData;

    public DataHandler() {
        initSwithThread();
    }

    /**
     * 发送数据,供外部调用
     * @param data
     */
    public void sendData(String data) {
        // 拷贝数据
        mData = data;
    }

    private void initSwithThread() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true) {
                    if(null != mData && mData.length() > 0) {
                        System.out.println("process data, run in thread : "
                                + Thread.currentThread().getName() + ", data = " + mData);
                        // 数据发送后,清除数据副本mData
                        mData = null;
                    }
                    // 为了能够清晰看清结果这里让thread休眠1s
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "ThreadB").start();
    }
}

测试类ThreadTest中创建线程A,然后在A中调用DataHandler实例的数据拷贝方法sendData()将数据切换到线程B中处理。

public class ThreadTest {

    public static DataHandler mHandler;

    public static void main(String[] args) {

        mHandler = new DataHandler();

        Thread threadA = new Thread(new Runnable() {

            @Override
            public void run() {
                // 线程A中发送数据
                String data = "hello code 9527";
                System.out.println("send data, run in thread : "
                        + Thread.currentThread().getName() + ", data = " + data);
                // 通过DataHandler将数据拷贝到线程B中处理
                mHandler.sendData(data);

            }
        }, "threadA");
        threadA.start();

    }

}

运行结果:
send data, run in thread : threadA, data = hello code 9527
process data, run in thread : ThreadB, data = hello code 9527


从结果可以看出数据“hello code 9527”在线程A中被DataHandler拷贝出来,副本存放到DataHandler中,然后通过线程B中进行处理。这样就实现了数据在线程间的切换。实现切换的“灵魂操作”便是“数据拷贝”和“目标线程对拷贝副本的轮询”。实现原理是不是很简单?其实Android的Handler机制也是基于这种原理实现的,有兴趣的同学可以深入分析一下Handler源码。

11-01 10:03