技术Android知识Android开发

Android 多线程和线程池

2017-05-19  本文已影响204人  秀花123

Android 多线程的可以归纳为两种情况:
1、将任务从工作线程抛到主线程;
2、将任务从主线程抛到工作线程;

一、将任务从工作线程抛到主线程

1、Handler#sendXXXMessage 方法

sendXXXMessage 方法共有七个:

public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean sendMessageAtFrontOfQueue(Message msg)

2、Handler#postRunnable(Runnable)方法

postXXX 系列方法有四个

public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postAtFrontOfQueue(Runnable r)

其实内部都是调用 getPostMessage 把 Runnable 封装成 Message 对象的 callback 属性,然后调用 sendXXXMessage 系列方法

3、Activity.runOnUIThread(Runnable)方法

public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

如果 Activity 在 UI 线程,直接运行该 Runnable 对象的 run 方法,如果不在 UI 线程,通过 Activity 持有的 Handle 对象调用 post 方法

4、View.post(Runnable)方法

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

5、AyscTask

@MainThread
protected void onPreExecute() {}
@MainThread
protected void onPostExecute(Result result) {}
@MainThread
protected void onProgressUpdate(Progress... values) {}

二、将任务从主线程抛到工作线程

1、Thread,Runnable

继承 Thread 或者实现 Runnable 接口

2、AyscTask

@WorkerThread
protected abstract Result doInBackground(Params... params);

3、HandlerThread

该类继承自 Thread,在普通的线程中是没有 Looper 对象的,在该线程的 run 方法中调用 Looper.prepare()Looper.loop() 开启消息循环,这样就允许在 HandlerThread 中创建 Handler 了。

HandleThread#run
一般的使用步骤是:
创建一个 HandlerThread 对象并调用 HandlerThraed#start() 方法启动线程,然后调用 HandlerThread#getLooper() 获取 Looper 对象作为参数创建 Handler 对象

4、IntentService

该类继承自 Service 类,在 onCreate 方法中开启了一个 HandlerThread ,并把该线程的 Looper 对象作为参数创建一个 Handler 对象:


IntentService#onCreate

内部定义了 Handler 的子类 ServiceHandler,在 handleMessage 方法中回调 onHandleIntent 方法,所以在使用 IntentService 时在 onHandleIntent 方法中处理耗时操作


ServiceHandler

三、线程池

什么时候使用线程池
使用线程池的优点:

线程池相关类

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,//核心池的大小
                              int maximumPoolSize,//线程池最大线程数
                              long keepAliveTime,//保持时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务队列
                              ThreadFactory threadFactory,//线程工厂
                              RejectedExecutionHandler handler) //异常的捕捉器
}

相关参数:

线程池策略

(1)当 currentSize < corePoolSize 时,直接启动一个核心线程并执行任务。
(2)当 currentSize >= corePoolSize、并且 workQueue 未满时,添加进来的任务会被安排到 workQueue 中等待执行。
(3)当 workQueue 已满,但是 currentSize < maximumPoolSize 时,会立即开启一个非核心线程来执行任务。
(4)当 currentSize >= corePoolSize、workQueue 已满、并且
currentSize > maximumPoolSize 时,调用 handler 默认抛出
RejectExecutionExpection 异常。

主要方法
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
 
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

工作线程数小于 核心线程数,调用 addWorker 方法创建一个新的线程
线程池中的每一个线程被封装成一个 Worker 对象,ThreadPool 维护的其实就是一组 Worker 对象。

public void execute(Runnable command)//提交任务
public void shutdown()//正在执行任务的线程执行完后关闭
public List<Runnable> shutdownNow()//立即关闭大部分线程

Executors

提供了一些静态方法,帮助我们方便的生成一些常用的线程池:
1)newSingleThreadExecutor

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2)newFixedThreadPool

newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3)newCachedThreadPool

newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4)newScheduledThreadPool

newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
ScheduledThreadPoolExecutor 有一系列的 scheduleXXX 方法:

public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit)
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay,TimeUnit unit) 
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit)

execute 方法和 submit 方法内部都是调用了 schedule 方法

public void execute(Runnable command) {
        schedule(command, 0, NANOSECONDS);
    }
public Future<?> submit(Runnable task) {
        return schedule(task, 0, NANOSECONDS);
    }

public <T> Future<T> submit(Runnable task, T result) {
        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
    }

public <T> Future<T> submit(Callable<T> task) {
        return schedule(task, 0, NANOSECONDS);
    }

线程池管理类

定义一个线程池管理类

public class ThreadManager {

    private ThreadPoolProxy longPool;
    private ThreadPoolProxy shortPool;

    private ThreadManager() {

    }

    private static ThreadManager instance = new ThreadManager();

    public static ThreadManager getInstance() {
        return instance;
    }

    public ThreadPoolProxy createLongThreadPool() {
        if (longPool == null) {
            longPool = new ThreadPoolProxy(5, 5, 5000);
        }
        return longPool;
    }

    public ThreadPoolProxy createShortThreadPool() {
        if (shortPool == null) {
            shortPool = new ThreadPoolProxy(3, 3, 5000);
        }
        return shortPool;
    }


    public class ThreadPoolProxy {
        private ThreadPoolExecutor executor;
        private int corePoolSize;
        private int maximumPoolSize;
        private long time;

        public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long time) {
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.time = time;
        }

        public void execute(Runnable runnable) {
            if (executor == null) {
                executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, time, TimeUnit.MILLISECONDS,
                        new LinkedBlockingQueue<Runnable>(10));
            }
            executor.execute(runnable);
        }

        public void cancel(Runnable runnable) {
            if (executor != null && !executor.isShutdown() && !executor.isTerminated())
                executor.remove(runnable);
        }
    }
}

上一篇下一篇

猜你喜欢

热点阅读