android的线程和线程池

 本文是android开发艺术探索的第11章的读书笔记,详细内容请移步看书中的第11章,不得不说这本书真的是干货满满,每一章每一次看都有不同的收获。
 

前言

1.线程分为主线程和子线程,主线程主要处理和界面相关的事情,而子线程则往往用于耗时操作。
2.AsyncTask底层是线程池;IntentService/HandlerThread底层是线程;HandlerThread是具有消息循环的线程,内部可以使用handler;IntentService是一个服务,内部采用HandlerThread来执行任务,完成后会自动退出,很像后台线程,但由于是服务 存活率高。
3.如果在一个进程中频繁的创建和销毁线程,这显然不是高效的做法,正确的做法是采用线程池,一个线程池会缓存一定数量的线程,通过线程池就可以避免因为频繁创建的销毁线程所带来的系统开销。
 

主线程和子线程

主线程:

主线程是指进程所拥有的线程,在Java中默认情况下一个进程只有一个线程,这个线程就是主线程。主线程只要处理界面交互相关的逻辑。

子线程:

因为主线程在任何时候都必须有较高的相应速度,否则就会产生一种界面卡顿的感觉,为了保持比较高的相应速度,这就要求主线程中不能执行耗时的任务,这个时候就需要工作线程,也就是子线程去完成。在android中,除了主线程之外的都是子线程。

AsyncTack的执行过程

  AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。AsyncTask不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。
 
 AsyncTask是一个抽象泛型类,它提供了Params, Progress, Result这三个泛型参数,第一个参数Params 表示参数的类型,Progress表示后天任务的执行进度类型,Result表示后台任务类型返回的结果的类型,如果AsyncTask不需要传递具体的参数,这三个参数可以使用Void来代替。
public abstract class AsyncTask<Params, Progress, Result> {
}
AsyncTask四个核心方法:
 
1、onPreExecute: 在主线程执行,在异步任务执行之前执行,为执行操作提供一些准备操作。
 
2、doInBackground: 在线程池中执行,该方法用于异步执行,此方法中可以通过publishProgress方法更新任务进度,publishProgress方法会调用onProgressUpdate,在执行完成之后,会将执行结果返回给onPostExecute方法。
 
3、onProgressUpdate: 在主线程执行,任务进度。
 
4、onPostExecute: 在主线程执行,任务处理结果。
 
这几个方法会先执行onPreExecute,接着执行doInBackground,如果在doInBackground方法中调用了publishProgress方法,接着会调用onProgressUpdate来处理任务进度,最后调用onPostExecute方法。
 
一般使用方法为:
 
 new MyAsyncTask().execute(params1,params2,params3);
execute方法的参数是 execute(Params... params) 其中...是参数的数量不定,他是一种数组型的参数,AsyncTask会依次执行传入的params任务。

1.AsyncTask的对象必须在主线程中创建
2、execute方法必须在主线程调用
3、不要在程序中直接调用onPreExecute,doInBackground,onProgressUpdate,onPostExecute方法。
4、一个AsycnTask对象只能执行一次,即只能调用一次execute方法,否则会报错。
5、在3.0之后,才同时支持了线行和并行的执行任务,如果要并行执行,调用AsyncTask#executeOnExecutor()

执行原理:

先看AsyncTask构造方法

扫描二维码关注公众号,回复: 719374 查看本文章
 
public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
 
 
            public Result call() throws Exception {
                mTaskInvoked.set(true);
 
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(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);
                }
            }
        };
    }
 

在AsyncTask的构造方法中,new了mWorker对象并重写了call方法,然后将mWorker作为参数传入了FutureTask的构造方法中,我们看一下FutureTask构造方法做了什么事

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
 
 
        this.state = NEW;       // ensure visibility of callable
    }
 

mWorker在FutureTask是callable,并保存到了FutureTask。

下面看AsyncTask的最重要的execute方法

 
 @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方法(前面说到了使用限制),接着调用了

onPreExecute()方法,所以这个方法最先执行可以在这个方法中做一些初始化操作。接着将参数传入了mWorker中了,前面看到mWorker作为参数传入到了mFuture中了,所以调用了Executor的execute方法,这个exec看上面传入进来的是sDefaultExecutor。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
 
 
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

可以看到sDefaultExecutor是SerialExecutor,

 
private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
 
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
 
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
在SerialExecutor的execute的方法中,mFuture作为Runnable传递过来。可以看到内部使用的是ArrayDeque队列,所以sDefaultExecutor事件上是一个串行的线程池,一个进程中的所以AsyncTask全部在这个串行的线程池中排队执行。
 
这个FutereTask会交给SerialExecutor的execute方法处理,SerialExecutor的execute 方法首先会把 FutereTask 插入到任务队列mTask中,如果这个时候没有正在活动的AsyncTask任务,那么就会调用SerialExecutor的scheduleNext方法来执行下一个任务,同时当AsyncTask任务执行完毕后,AsyncTask会继续执行其他任务知道所有的任务都执行为止,从这里可以看出,在默认情况下AsyncTask是串行执行的。
 
接着分析实现方法,我们知道了r实际上就是mFuture,我们来看一下run方法中执行了什么。
 public void run() {
       。。。
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    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);
        }
    }
从上面分析中我们知道了mFuture中的callable其实是mWorker,在这个方法中调用了callable的call方法实际上就是调用了mWorker的call方法。
 
mWorker的call方法
public Result call() throws Exception {
        mTaskInvoked.set(true);
 
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        Result result = doInBackground(mParams);
 
 
        Binder.flushPendingCommands();
        return postResult(result);
    }
 
先将mTaskInvoked设置为true,表示当前任务已经被调用了,然后执行 doInBackground 方法,然后将其返回值传递给postResult方法。
 private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
 
getHandler方法
private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
 
 
            }
            return sHandler;
        }
    }
 
Handler其实是InternalHandler。就是postResult方法通过sHandler发送一个MESSAGE_POST_RESULT的消息,
 
 private static InternalHandler sHandler;
 
private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }
 
        @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;
            }
        }
    }
 
可以看到,sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler的对象必须在主线程中创建。所以AsyncTask的类同样必须在主线程中检查。
 
sHandler在收到MESSAGE_POST_RESULT的消息后会调用AsyncTask的finish方法。
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
 
如果AsyncTask被取消执行了,那么就调用onCancelled方法,否则调用 onPostExecute方法。到了这里整个AsyncTask的执行流程就分析完成了。
 

HandlerThread

 HandlerThread继承了Thread,是一种可以使用Handler的Thread;在run方法中通过looper.prepare()来开启消息循环,这样就可以在HandlerThread中创建Handler了;外界可以通过一个Handler的消息方式来通知HandlerThread来执行具体任务;确定不使用之后,可以通过quit或quitSafely方法来终止线程执行;具体使用场景是IntentService。


IntentService

 IntentSercie是一种特殊的Service,继承了Service并且是抽象类,任务执行完成后会自动停止,优先级远高于普通线程,适合执行一些高优先级的后台任务;
 IntentService封装了HandlerThread和Handler,onCreate方法自动创建一个HandlerThread,然后用它的Looper构造了一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息都会在HandlerThread执行;
 IntentServiced的onHandlerIntent方法是一个抽象方法,需要在子类实现,onHandlerIntent方法执行stopSelt(int startId)就会停止服务,如果存在多个后台任务,执行完最后一个stopSelf(int startId)才会停止服务
 

Android中的线程池

线程池的优点:

  • 1、重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销
  • 2、能有效的控制线程池的最大并发数,避免大量的线程之间因为抢占系统资源而导致的阻塞现象
  • 3、能够对线程进行简单的管理,并提供定时执行和指定之间间隔执行的功能

ThreadPoolExecutor

ThreadPoolExecutor是线程池的真正实现,它的构造器方法提供了一系列参数来配置线程池

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
 
 
                              RejectedExecutionHandler handler) {
}
  • CorePoolSize: 线程池的核心线程数,默认情况下,核心线程会在线程中一直存活,即使他们处于空闲状态。如果将ThreadPoolExecutor的allowCoreThreadTimeTout的属性设置为true,那么闲置的线程在等待新任务到来时会有超时策略,这个时间由keepAliveTime决定,当等待的时间超过了keepAliveTime指定的时长后,核心线程池就会被终止。
  • maximumPoolSize:
  • keepAliveTime: 非核心线程的超时时长,超过这个时长,非核心线程就被回收。当ThreadPoolExecutor的allowCoreThreadTimeTout的属性设置为true,keepAliveTime同样会作用于核心线程。
  • unit: 用于指定keepAliveTime参数的时间单位
  • workQueue: 线程中的任务线程,通过线程池execute方法提交的runnable对象就存储在这个参数中
  • threadFactory: 线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口,它只有一个方法:Thread newThread(Runnable runnable)
  • handler: 当线程池无法执行新任务时,进行调度

ThreadPoolExecutor执行任务大致遵循的规则

  • 1、如果线程池中的线程数量没有达到核心线程池的数量,那么会直接启动一个核心线程来执行任务。
  • 2、如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务就会插入到任务队列等待执行。
  • 3、如果在步骤2中无法将任务插入到任务列表中,这往往是由于任务队列已满,这个时候如果线程数量未达到线程池规定的最大值,那么会立即启动一个非核心线程来执行任务
  • 4、如果步骤3中的线程数量已经达到线程池规定的最大值,那么久拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法通知调用者。

线程池的分类

FixedThreadPool

通过Executors的newFixedThreadPool方法来创建。它是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池关闭。当所有的线程都处于活动状态时,新任务就处于等待状态,直到有线程空出来,由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速的相应外界的请求。newFixedThreadPool方法的实现如下,可以发现FixedThreadPool中只有核心线程并且这些核心线程没有超过机制,另外任务线程也是没有大小限制的。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
 
 
}

参数是指定核心线程数大小,可以看出来核心线程数 == 最大可活动线程数,所以FixedThreadPool只有核心线程。

CacheThreadPool

通过Executors的newCachedThreadPool方法来创建。它是一种线程数量不定的线程池,它只有非核心线程,并且其最大线程数量为Integer.MAX_VALUE。实际上相当于线程数量可以任意大。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则会利用空闲的线程来处理新任务。线程池中的线程都是有超时机制的,这个超时时长为60秒,超过60秒闲置线程就会被回收。和FixedThreadPool不同的是,CachedThreadPool的任务集合其实相当于一个空集合,这将导致所有任务都是立即执行,因为这种模式下SynchronousQueue是无法插入到任务队列的。 从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务。当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止。这个时候CachedThreadPool之中实际上是没有任何线程的。它几乎是不占用任何系统资源的。newCachedThreadPool的方法实现如下:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 
 
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
 

ScheduledThreadPool

通过Executors的newScheduledThreadPool方法创建。它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时,立即回收。ScheduleThreadPool这类线程池主要用于执行定时任务和具有固定周期的重复任务

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
 
 
}

SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法创建。这类线程池内只有一个核心线程,它确保所有的任务都在同一个线程中顺序执行。SingleThreadExecutor的意思在于统一所有的外界任务在一个线程中,这就使得这些任务之间不需要处理线程同步问题了。

 public static ExecutorService newSingleThreadExecutor() {
 
 
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
前面的来自Android开发艺术探索,后面的来自 https://blog.csdn.net/wanggang514260663/article/details/77984099
 
 

猜你喜欢

转载自www.cnblogs.com/gxl1995/p/9032277.html