Android高级进阶

2019-07-30-Android 多线程的实现:Thread

2019-08-04  本文已影响0人  王元

1,Thread

线程是Java语言的一个概念,是实际执行任务的最小单元

public class MyThead extends Thread {
    @Override
    public void run() {
        super.run();
        //执行具体的业务逻辑
    }
}

启动线程

public void startThead() {
    MyThead thead = new MyThead();
    thead.start();
}

2,实现接口,并且实现run方法

public class MyRunable implements Runnable {
    @Override
    public void run() {
        //具体的业务逻辑
    }
}

启动runable

Thread thread = new Thread(new MyRunable());
thread.start();

Android应用中各种类型的线程,本质都是Linux系统的pthreads,在应用层分为各种线程

2,HanderThead

HandlerThread是一个集成了Looper和MessageQueue的线程,当启动HandlerThread的时候,会同时创建一个looper和MessageQueue,然后等待消息去处理,下面是run方法的源码

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

它的使用方法和普通的线程是一样的,方法如下:

public void usehandlerThread() {
    HandlerThread thread = new HandlerThread("use-handlethread");
    thread.start();
    Handler mHandler = new Handler(thread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };
}

HandlerThread只有一个消息队列,队列的消息是顺序执行的,因此是线程安全的,当然吞吐量会收到一定的影响.

HandlerThread的内部机制确保了,在创建lopper和发送消息之间不存在竞态条件,这是通过HandlerThread.getLooper()实现为一个阻塞操作实现的,只有当HandlerThread准备好接受消息的时候才会返回

public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    // 如果线程已经启动,那么在looper准备好之前,应该先等待
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

如果某些业务下,需要在HandlerThread开始接收消息前执行一些操作,比如初始化Handler,可以继承HandlerThread来做

public class MyHandlerThread extends HandlerThread {
    public MyHandlerThread(String name) {
    super("MyHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
    }
    
    private Handler mHandler;
    @Override
    protected void onLooperPrepared() {
        super.onLooperPrepared();
        mHandler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
    }
        
    public  void uploadMsg(Message message) {
        if(mHandler != null)mHandler.sendMessage(message);
    }
}

3,AsyncQueryHander

4,IntentService

为了能够在Service内实现在子线程中执行耗时任务,Android
引入了IntentService,但依旧使用的是HanderThread

本身就是一个Service,可以通过context.startService启动

IntentServie是一个抽象类,需要我们使用前继承,并实现onHandleIntent(Intent intent);方法,同时在子类的构造方法中调用super(String name)传入子类名字

public class MyIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService(String name) {
        super(MyIntentService.class.getName());
        setIntentRedelivery(true);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        // 这个方法在后台线程中调用,原因是IntentService内部的handler绑定的是自线程的looper
    }
}

上面代码中setIntentRedelivery方法如果设置为true,那么IntentService的onstartCommand方法将返回START_REDELIVER_INTENT,这时如果onHandleIntent在返回前被进程杀死掉了。那么进程将重新启动,Intent将重新投递。

5,Java线程池 Executer Framwork

我们知道创建和销毁对象,是存在开销的(例如线程),这些会影响我们的性能,使用Java Executer框架可以通过线程池解决这一问题,Executer框架提供了如下能力

Executer是一个接口,主要目的就是分离任务的创建和执行,实现上面的功能点

public interface Executor {
    void execute(Runnable command);
}

当需要实现自己的线程池的时候。只有实现Executor接口,并实现execute方法,最简单的实现就是创建线程执行任务

public class MyExecutor implements Executor {
    @Override
    public void execute(Runnable command) {
        new Thread(command).start();
    }
}

当然实际应用的Executor很少是这么简单的,需要增加类似队列,任务优先级等功能,最终实现线程池

线程池是任务队列和工作线程的集合,这俩者结合起来实现生产者和消费者模式

Executor已经为我们提供了几个预定义的线程池实现,如下

当有新的任务需要处理的时候,线程会创建新的线程来处理它

空闲的线程会等待60s来执行新任务,当没有可执行的任务,就会自动销毁

因此线程池的大小会根据队列的大小变化而变化

以上就是预定义的线程池,它们都是基于ThreadPoolExecutor类的基础上构建的,而通过ThreadPoolExecutor我们可以自定义线程池的一些行为。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)

6,AsyncTask

AsyncTask时在Executors框架基础上的封装,它实现了耗时任务移动到工作线程中执行,同时提供方便的接口实现工作线程和主线程的通信

public class MyAsyncTask extends AsyncTask<Integer, Integer, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //主线程
    }

    @Override
    protected String doInBackground(Integer... integers) {
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer[] values) {
        super.onProgressUpdate(values);
        //主线程
    }

    @Override
    protected void onPostExecute(String o) {
        super.onPostExecute(o);
        //主线程
    }
}

我们知道在不同的Android版本中对AsycTask的实现不尽相同,在不同的版本的表现区别如下

API level execute方法 executeOnExecutor方法
1~3 串行执行 没有这个方法
4~10 并行执行 没有这个方法
11~12 并行执行 串行或者并行
13+ 串行执行 串行或者并行

可以看到在api 13+建议使用executeOnExecutor方法代替execute

一个应用中所使用的所有Async实例会共享全局的属性,也就是说如果AsyncTask中的任务时串行执行,那么应用中的所有AsyncTask都会排队,只有等前一个任务执行完成,才会执行下一个任务
如果AsyncTask执行的是异步任务,那么在4核CPU系统上最多也只有5个任务同时进行,其余任务需要在队列中排队,等待空闲的线程,原因是AsyncTask中指定的核心线程数是CPU核数+1

7,Loader

Loader 是Android3.0开始引入的一个异步数据加载框架,这里暂时不做更多介绍,以后补充

上一篇下一篇

猜你喜欢

热点阅读