Android的线程和线程池--《Android开发艺术探索》阅读笔记——第十一章

Android的线程和线程池--《Android开发艺术探索》阅读笔记——第十一章,第1张

概述文章目录一、Android中的线程形态1.1AsyncTask1.1.1使用方法1.1.2原理分析:1.2HandlerThread1.3IntentService二、Android中的线程池2.1ThreadPoolExecutor2.2线程池的分类2.2.1FixedThreadPool2.2.2CachedThreadPool2.2.3ScheduledThreadPool2.2.4SingleThreadEx

文章目录一、Android中的线程形态1.1 AsyncTask1.1.1 使用方法1.1.2 原理分析:1.2 HandlerThread1.3 IntentService二、Android中的线程池2.1 ThreadPoolExecutor2.2 线程池的分类2.2.1 FixedThreadPool2.2.2 CachedThreadPool2.2.3 ScheduledThreadPool2.2.4 SingleThreadExecutor

除了Thread,AndroID中扮演线程的角色还有:AsyncTask、HandlerThread、IntentService。

AsyncTask:内部封装线程池、handler,便于在子线程中更新UI。HandlerThread:可以使用消息循环的线程,在它内部可以使用Handler。IntentService:内部使用HandlerThread执行任务,完毕后会自动退出。(相比后台线程)因是组件,优先级高,不易被杀死。

线程是 *** 作系统调度的最小单元,是一种受限的资源,不可能无限制的产生。且线程的创建和销毁需要相应的开销。且存在大量线程时,系统会通过时间片轮转的方式调度线程,因此线程不可能做到并行,除非线程数小于等于cpu数。所以需要 线程池,它可以缓存一定数量的线程,避免频繁地线程创建和销毁带来的系统开销。

一、AndroID中的线程形态1.1 AsyncTask

AsyncTask是用来在线程池中处理异步任务,并可以把处理进度和结果发送到UI线程。

1.1.1 使用方法

AsyncTask的基本使用方法,示例如下:

    private voID testAsyncTask() {        //一般要在主线程实例化。(实际在9.0上 子线程创建实例然后主线程execute没问题)        //三个泛型参数依次表示参数类型、进度类型、结果类型。        //覆写的这几个方法不可以直接调用        AsyncTask<Integer, Integer, String> task = new AsyncTask<Integer, Integer, String>() {            @OverrIDe            protected voID onPreExecute() {                super.onPreExecute();                //主线程执行,在异步任务之前                Log.i(TAG, "testAsyncTask onPreExecute: ");            }            @OverrIDe            protected String doInBackground(Integer... integers) {                Log.i(TAG, "testAsyncTask doInBackground: ");                //任务在 线程池中执行 耗时 *** 作                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printstacktrace();                }                //发出进度                publishProgress(50);                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printstacktrace();                }                //再发出进度                publishProgress(100);                return "我是结果。参数是" + integers[0];            }            @OverrIDe            protected voID onPostExecute(String s) {                super.onPostExecute(s);                //在主线程执行,在异步任务执行完之后                Log.i(TAG, "testAsyncTask onPostExecute: "+s);            }            @OverrIDe            protected voID onProgressUpdate(Integer... values) {                super.onProgressUpdate(values);                //执行在主线程,调用publishProgress()后就会执行                Log.i(TAG, "testAsyncTask onProgressUpdate: 进度:"+values[0]+"%");            }            @OverrIDe            protected voID onCancelled() {                super.onCancelled();                //取消任务            }        };        //必须要在主线程执行execute,且只能执行一次        task.execute(100);    }

执行结果日志如下:

2020-01-14 11:29:03.510 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onPreExecute: 2020-01-14 11:29:03.511 13209-13282/com.hfy.demo01 I/hfy: testAsyncTask doInBackground: 2020-01-14 11:29:04.558 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onProgressUpdate: 进度:50%2020-01-14 11:29:05.589 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onProgressUpdate: 进度:100%2020-01-14 11:29:05.590 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onPostExecute: 我是结果。参数是100
1.1.2 原理分析:

先看构造方法

    public AsyncTask() {        this((Looper) null);    }    public AsyncTask(@Nullable Handler handler) {        this(handler != null ? handler.getLooper() : null);    }    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask(@Nullable Looper callbackLooper) {        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()            ? getMainHandler()            : new Handler(callbackLooper);        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Result result = null;                try {                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                    //noinspection unchecked                    result = doInBackground(mParams);                    Binder.flushPendingCommands();                } catch (Throwable tr) {                    mCancelled.set(true);                    throw tr;                } finally {                	//执行完,发出结果                    postResult(result);                }                return result;            }        };        mFuture = new FutureTask<Result>(mWorker) {            @OverrIDe            protected voID done() {                try {                    postResultIfnotinvoked(get());                } catch (InterruptedException e) {                    androID.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                    throw new RuntimeException("An error occurred while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfnotinvoked(null);                }            }        };    }    private static Handler getMainHandler() {        synchronized (AsyncTask.class) {            if (sHandler == null) {            	//这里传入的是主线程的looper,所以用来把消息切到主线程                sHandler = new InternalHandler(Looper.getMainLooper());            }            return sHandler;        }    }

看到,首先使用主线程的Looper创建了InternalHandler实例。然后创建了WorkerRunnable的实例mWorker,call方法中看到调用了 doInBackground(mParams),可以猜想call方法是执行在线程池的。然后创建了FutureTask的实例mFuture并传入了mWorker,mFuture怎么使用的呢?后面会分析道。我们可以先看下Handler的实现InternalHandler:

    private static class InternalHandler extends Handler {        public InternalHandler(Looper looper) {            super(looper);        }        @SuppressWarnings({"unchecked", "RawUSEOfParameterizedType"})        @OverrIDe        public voID handleMessage(Message msg) {            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;            switch (msg.what) {                case MESSAGE_POST_RESulT:                    // There is only one result                    result.mTask.finish(result.mData[0]);                    break;                case MESSAGE_POST_PROGRESS:                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }

看到有处理发送结果、处理发送进度的消息。消息从哪发来的呢?先留个疑问。继续看AsyncTask的execute方法:

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;    /**     *  串行 执行器     */    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();        @MainThread    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }    @MainThread    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,            Params... params) {        if (mStatus != Status.PENDING) {            switch (mStatus) {                case RUNNING:                    throw new IllegalStateException("Cannot execute task:"                            + " the task is already running.");                case FINISHED:                    throw new IllegalStateException("Cannot execute task:"                            + " the task has already been executed "                            + "(a task can be executed only once)");            }        }        mStatus = Status.RUNNING;        onPreExecute();        mWorker.mParams = params;        exec.execute(mFuture);        return this;    }

execute方法走到了executeOnExecutor方法,先进行当前任务状态的判断,默认是准备执行任务的PENDING状态,然后变为RUNNING。但如果正在执行的RUNNING、执行完的FINISHED都会抛出异常。这也是一个任务实例只能执行一次的原因。然后又走到了onPreExecute(),因为execute执行在UI线程 所以也解释了其是执行在UI线程的原因。接着把参数赋值给mWorker,mFuture作为参数执行 静态的sDefaultExecutor的execute()方法。注意到sDefaultExecutor是SerialExecutor实例,去瞅瞅:

	//线程池    public static final Executor THREAD_POol_EXECUTOR;    static {        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(                CORE_POol_SIZE, MAXIMUM_POol_SIZE, KEEP_AliVE_SECONDS, TimeUnit.SECONDS,                sPoolWorkQueue, sThreadFactory);        threadPoolExecutor.allowCoreThreadTimeOut(true);        THREAD_POol_EXECUTOR = threadPoolExecutor;    }        private static class SerialExecutor implements Executor {        final arraydeque<Runnable> mTasks = new arraydeque<Runnable>();        Runnable mActive;		//execute方法加了锁        public synchronized voID execute(final Runnable r) {        	//把r存入到任务队列的队尾            mTasks.offer(new Runnable() {                public voID run() {                    try {                        r.run();                    } finally {                    	//任务执行完,就执行下一个                        scheduleNext();                    }                }            });            //把r存入任务队列后,然后当前没有取出的任务,就 取 队列头部 的任务执行            if (mActive == null) {                scheduleNext();            }        }        protected synchronized voID scheduleNext() {        	//取 队列头部 的任务执行            if ((mActive = mTasks.poll()) != null) {            	//THREAD_POol_EXECUTOR是线程池                THREAD_POol_EXECUTOR.execute(mActive);            }        }    }

上面都有注释,可见SerialExecutor就是串行执行器,最终执行在THREAD_POol_EXECUTOR的线程池中。r.run()实际走的是FutureTask的run方法:

    public FutureTask(Callable<V> callable) {        if (callable == null)            throw new NullPointerException();        this.callable = callable;        this.state = NEW;       // ensure visibility of callable    }        public voID run() {        if (state != NEW ||            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))            return;        try {            Callable<V> c = callable;            if (c != null && state == NEW) {                V result;                boolean ran;                try {                                	//callable的call方法                    result = c.call();                                        ran = true;                } catch (Throwable ex) {                    result = null;                    ran = false;                    setException(ex);                }                if (ran)                    set(result);            }        } finally {            // runner must be non-null until state is settled to            // prevent concurrent calls to run()            runner = null;            // state must be re-read after nulling runner to prevent            // leaked interrupts            int s = state;            if (s >= INTERRUPTING)                handlePossibleCancellationInterrupt(s);        }    }

FutureTask的run方法中调用的传入的callable的call()方法,再结合上面AsyncTask的构造方法,mWorker就是实现callable的call()方法。所以里面的doInBackground方法就会串行的执行在线程池中。因为串行,那使用execute方法不能执行特别耗时的任务,否则会阻塞后面等待的任务。若想要并行,可采用AsyncTask的executeOnExecutor方法,传入线程池THREAD_POol_EXECUTOR即可。

还注意到,doInBackground执行完后调用了postResult(result),result就是doInBackground返回值:

    private Handler getHandler() {        return mHandler;    }    private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = getHandler().obtainMessage(MESSAGE_POST_RESulT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }

看到,使用handler发送消息,消息类型就是MESSAGE_POST_RESulT,前面看到InternalHandler内部handleMessage是有处理的,就是调用task的finish方法:

    private voID finish(Result result) {        if (isCancelled()) {        	//如果任务取消了,回调onCancelled            onCancelled(result);        } else {        	//没有取消            onPostExecute(result);        }        //修改任务状态为完成        mStatus = Status.FINISHED;    }

可见如果没有调用cancel(),就会走onPostExecute,所以onPostExecute也是执行在UI线程的。

最后看下publishProgress方法:

    protected final voID publishProgress(Progress... values) {        if (!isCancelled()) {            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();        }    }

如果没有取消任务,也是用handler,消息类型就是MESSAGE_POST_PROGRESS,前面看到InternalHandler内部handleMessage是有处理的,最后在UI线程执行onProgressUpdate方法。

举两个例子 总结

以上是内存溢出为你收集整理的Android的线程和线程池--《Android开发艺术探索》阅读笔记——第十一章全部内容,希望文章能够帮你解决Android的线程和线程池--《Android开发艺术探索》阅读笔记——第十一章所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1067838.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存