android的线程和线程池
前言
主线程和子线程
主线程:
主线程是指进程所拥有的线程,在Java中默认情况下一个进程只有一个线程,这个线程就是主线程。主线程只要处理界面交互相关的逻辑。
子线程:
因为主线程在任何时候都必须有较高的相应速度,否则就会产生一种界面卡顿的感觉,为了保持比较高的相应速度,这就要求主线程中不能执行耗时的任务,这个时候就需要工作线程,也就是子线程去完成。在android中,除了主线程之外的都是子线程。
AsyncTack的执行过程
public abstract class AsyncTask<Params, Progress, Result> { }
2、doInBackground: 在线程池中执行,该方法用于异步执行,此方法中可以通过publishProgress方法更新任务进度,publishProgress方法会调用onProgressUpdate,在执行完成之后,会将执行结果返回给onPostExecute方法。
3、onProgressUpdate: 在主线程执行,任务进度。
4、onPostExecute: 在主线程执行,任务处理结果。
new MyAsyncTask().execute(params1,params2,params3);
1.AsyncTask的对象必须在主线程中创建
2、execute方法必须在主线程调用
3、不要在程序中直接调用onPreExecute,doInBackground,onProgressUpdate,onPostExecute方法。
4、一个AsycnTask对象只能执行一次,即只能调用一次execute方法,否则会报错。
5、在3.0之后,才同时支持了线行和并行的执行任务,如果要并行执行,调用AsyncTask#executeOnExecutor()
执行原理:
先看AsyncTask构造方法
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); } } }
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); } }
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); }
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
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; } } }
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
HandlerThread
HandlerThread继承了Thread,是一种可以使用Handler的Thread;在run方法中通过looper.prepare()来开启消息循环,这样就可以在HandlerThread中创建Handler了;外界可以通过一个Handler的消息方式来通知HandlerThread来执行具体任务;确定不使用之后,可以通过quit或quitSafely方法来终止线程执行;具体使用场景是IntentService。
IntentService
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>())); }