首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全面理解:Android中的线程及线程池

全面理解:Android中的线程及线程池

作者头像
胡飞洋
发布2020-07-23 16:09:05
1K0
发布2020-07-23 16:09:05
举报

目录

  • 一、Android中的线程形态
    • 1.1 AsyncTask
      • 1.1.1 使用方法
      • 1.1.2 原理分析:
    • 1.2 HandlerThread
    • 1.3 IntentService
  • 二、Android中的线程池
    • 2.1 ThreadPoolExecutor
    • 2.2 线程池的分类
      • 2.2.1 FixedThreadPool
      • 2.2.2 CachedThreadPool
      • 2.2.3 ScheduledThreadPool
      • 2.2.4 SingleThreadExecutor

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

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

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

01

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方法。

举两个例子? 例子1,默认的串行执行:

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task1 SERIAL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task2 SERIAL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task3 SERIAL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();

执行结果如下,每隔两秒打印一次,可见是串行执行。

2020-01-16 14:51:40.836 13346-13599/com.hfy.demo01 I/hfy: task1 SERIAL_EXECUTOR doInBackground: 
2020-01-16 14:51:42.876 13346-13598/com.hfy.demo01 I/hfy: task2 SERIAL_EXECUTOR doInBackground: 
2020-01-16 14:51:44.915 13346-13599/com.hfy.demo01 I/hfy: task3 SERIAL_EXECUTOR doInBackground: 

例子2,并行执行-直接使用线程池:

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task1 THREAD_POOL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task2 THREAD_POOL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                Log.i(TAG, "task3 THREAD_POOL_EXECUTOR doInBackground: ");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

执行结果如下,同时打印出来,可见是并行执行。

2020-01-16 14:51:38.772 13346-13599/com.hfy.demo01 I/hfy: task1 THREAD_POOL_EXECUTOR doInBackground: 
2020-01-16 14:51:38.773 13346-13600/com.hfy.demo01 I/hfy: task2 THREAD_POOL_EXECUTOR doInBackground: 
2020-01-16 14:51:38.774 13346-13601/com.hfy.demo01 I/hfy: task3 THREAD_POOL_EXECUTOR doInBackground: 

总结一下,AsyncTask内部默认 使用串行执行器 串行地 在线程池 执行任务,我们也可以使用executeOnExecutor直接使用线程池并行执行。内部使用handler把进度和结果从线程池切换到UI线程。

1.2 HandlerThread

HandlerThread继承自Thread,内部已准备了Looper并已开启循环。所以可以在UI线程使用handler发送任务到HandlerThread中执行,且可以随意多次发送任务。(而普通thread执行完run方法中的耗时操作就结束了。)当不使用时 如onDestroy中,使用quit()或quitSafely()退出即可。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    //looper开启之前可以做一些事情
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        //给当前线程准备Looper实例
        Looper.prepare();
        //加锁,保证能获取到looer实例
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        //开启循环
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    //获取不到就等 run中的notifyAll()被调用
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    //直接退出
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    //安全退出(执行完正在正在执行的任务再退出)
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

举个例子?

    private void testHandlerThread() {
        HandlerThread handlerThread = new HandlerThread("HandlerThreadName");
        handlerThread.start();
        Handler handler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1000:
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Log.i(TAG, "handleMessage: thread name="+Thread.currentThread().getName()+",what="+msg.what);
                        break;
                    case 1001:
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Log.i(TAG, "handleMessage: thread name="+Thread.currentThread().getName()+",what="+msg.what);
                        break;
                    default:
                        break;
                }
            }
        };

        Log.i(TAG, "sendMessage thread name="+Thread.currentThread().getName());
        handler.sendMessage(Message.obtain(handler, 1000));
        handler.sendMessage(Message.obtain(handler, 1001));
    }

可见在主线程发送了两个任务,顺序执行在HandlerThread了。

2020-01-16 17:12:46.832 16293-16293/com.hfy.demo01 I/hfy: sendMessage thread name=main
2020-01-16 17:12:48.833 16293-17187/com.hfy.demo01 I/hfy: handleMessage: thread name=HandlerThreadName,what=1000
2020-01-16 17:12:49.834 16293-17187/com.hfy.demo01 I/hfy: handleMessage: thread name=HandlerThreadName,what=1001

1.3 IntentService

IntentService是继承自Service的抽象类,可执行后台耗时任务,执行完后会自动停止。因为是Service,即是Android的组件,优先级比单纯的线程高,不容易被系统杀死,所以可用来执行优先级高的后台任务,

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    //内部类handler
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //先回调出去,待IntentService子类覆写自己的逻辑
            onHandleIntent((Intent)msg.obj);
            //结束service自己,msg.arg1是标记某次startService的Id。
            //但如果此时外部又调用了startService,那么最新的请求id就不是msg.arg1了,所以下面这句就不会结束service。
            stopSelf(msg.arg1);
        }
    }
    //name是线程名
    public IntentService(String name) {
        super();
        mName = name;
    }
    ...
    @Override
    public void onCreate() {
        super.onCreate();
        //创建HandlerThread实例 并启动
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        //创建对应looper的handler,所以mServiceHandler的handleMessage执行在 线程中
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        //发送消息,参数是startId、intent
        //每次startService() 都会走这里
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        //退出looper循环
        mServiceLooper.quit();
    }

    ...

     //执行子在线程,同时只存在一个intent(因为looper的队列),所以如果此方法执行时间过长,会阻塞其他请求,所有请求执行完,service会自动停止,所以不能手动调用stopSelf。
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

onCreate中创建了HandlerThread实例,对应的Handler实例mServiceHandler,所以mServiceHandler发送的任务都会在线程中执行。 onStartCommand中调用的是onStart,onStart中确实使用mServiceHandler发送消息,携带的参数是startId、intent,startId是每次启动service的标记,intent就是启动service的intent。 onDestroy中退出looper循环。

发送的消息在哪处理的呢?

那就看ServiceHandler,其继承自Handler,handleMessage方法中先调用了抽象方法onHandleIntent((Intent)msg.obj),参数就是启动service的intent。所以IntentService 的子类必须要重写onHandleIntent,并处理这个intent。因为mServiceHandler拿到的HandlerThread的looper,所以这个onHandleIntent()就是执行在子线程中的。 接着调用了stopSelf(msg.arg1),msg.arg1)就是前面说的启动service的标记。对stopSelf(int startId)说明如下:

startId:代表启动服务的次数,由系统生成。 stopSelf(int startId):在其参数startId跟 最后启动该service时生成的ID相等时才会执行停止服务。 stopSelf():直接停止服务。 使用场景:如果同时有多个服务启动请求发送到onStartCommand(),不应该在处理完一个请求后调用stopSelf();因为在调用此函数销毁service之前,可能service又接收到新的启动请求,如果此时service被销毁,新的请求将得不到处理。此情况应该调用stopSelf(int startId)。

所以,当多次启动service,就会多次调用 onStart,那么会有多个任务发出,当每次任务执行完onHandleIntent时,stopSelf(int startId)中会判断,若又启动service那么就不会停止。那么looper继续取下个消息继续处理。直到stopSelf中的startId和最新启动的startId相同,就会停止。因为是looper,所以这些任务都是按启动service的顺序执行的。

举个例子?

    private void testIntentService() {

        Intent intent= new Intent(this, MyIntentService.class);
        intent.putExtra("task_name","task1");
        startService(intent);

        intent.putExtra("task_name","task2");
        startService(intent);

        intent.putExtra("task_name","task3");
        startService(intent);
    }

    public static class MyIntentService extends IntentService {

        public MyIntentService() {
            super("MyIntentServiceThread");
        }

        @Override
        protected void onHandleIntent(Intent intent) {            
            Log.i(TAG, "MyIntentService onHandleIntent: begin."+intent.getStringExtra("task_name"));
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG, "MyIntentService onHandleIntent: done."+intent.getStringExtra("task_name"));
        }

        @Override
        public void onDestroy() {
            Log.i(TAG, "MyIntentService onDestroy: ");
            super.onDestroy();
        }
    }
2020-01-17 09:58:44.639 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task1
2020-01-17 09:58:46.640 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task1
2020-01-17 09:58:46.641 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task2
2020-01-17 09:58:48.642 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task2
2020-01-17 09:58:48.644 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task3
2020-01-17 09:58:50.645 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task3
2020-01-17 09:58:50.650 11117-11117/com.hfy.demo01 I/hfy: MyIntentService onDestroy:

静态内部类MyIntentService继承IntentService并重写了onHandleIntent,就是睡两秒。然后不间断连续启动3次,由日志可见是顺序执行的,最后都执行完才走到onDestroy。

再看,如果是间隔三秒发送呢:

        private void testIntentService() {

        Log.i(TAG, "testIntentService: task1");
        Intent intent= new Intent(this, MyIntentService.class);
        intent.putExtra("task_name","task1");
        startService(intent);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "testIntentService: task2");
                intent.putExtra("task_name","task2");
                startService(intent);
            }
        }, 3000);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "testIntentService: task3");
                intent.putExtra("task_name","task3");
                startService(intent);
            }
        }, 3000);
    }
2020-01-17 10:16:29.335 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task1
2020-01-17 10:16:29.698 14739-14843/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task1
2020-01-17 10:16:31.698 14739-14843/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task1
2020-01-17 10:16:31.701 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy: 
2020-01-17 10:16:32.371 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task2
2020-01-17 10:16:32.390 14739-14862/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task2
2020-01-17 10:16:34.391 14739-14862/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task2
2020-01-17 10:16:34.451 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy: 
2020-01-17 10:16:35.339 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task3
2020-01-17 10:16:35.364 14739-14873/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task3
2020-01-17 10:16:37.364 14739-14873/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task3
2020-01-17 10:16:37.367 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy:

可见每个任务执行完 就走onDestroy了。这是因为当一个任务执行完,走到stopSelf(int startId)时,后面还没有再次开启service,所以此时的stopSelf中的startId就是最新的,所以就会停止服务了。

02

Android中的线程池

线程池优点如下:

  • 能够重用线程池中的线程,避免线程的创建、销毁带来的性能开销。
  • 能有效控制线程池中的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
  • 能对线程进行简单管理,并提供定时执行、指定间隔循环执行的功能。 Android中的线程池来源于Java的Executor,正在的实现是ThreadPoolExecutor。

2.1 ThreadPoolExecutor

ThreadPoolExecutor是线程池的真正实现,看下其构造方法里的参数,参数会影响线程池的功能特性。

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
  • corePoolSize,核心线程数,默认一般核心线程会在线程池中一直存活,即使处理空闲状态。但当allowCoreThreadTimeOut设置为true,那么核心线程就会有闲置超时时间,闲置超过超时时间就会终止。超时时间由keepAliveTime和unit指定。
  • maximumPoolSize,最大线程数,当活动线程到达这个数,后续的新任务会被阻塞。
  • keepAliveTime,非核心线程闲置时 的超时时长。非核心线程闲置时间超过此时间就会被回收。当allowCoreThreadTimeOut设置为true,keepAliveTime也会作用于核心线程。
  • unit,是keepAliveTime的时间单位,取值是枚举,有TimeUnit.MINUTES、TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。
  • workQueue,线程池中的任务队列,通过线程池的execute方法提交的Runnable会存在这个队列中。
  • threadFactory,线程工厂,为线程池提供创建新线程的能力。

还有个不常用参数RejectedExecutionHandler handler,调用其rejectedExecution()方法来处理 当任务队列已满 时 不能执行新任务的情况。handler的默认实现是AbortPolicy,rejectedExecution()中会直接抛出异常RejectedExecutionException。其他实现如DiscardPolicy的rejectedExecution()中是不做任何事。还有CallerRunsPolicy、DiscardOldestPolicy。

ThreadPoolExecutor执行任务的执行规则 如下:

  • 如果线程池中的线程数未到达核心线程数,那么会直接启动一个核心线程来执行这个任务。(不管已启动的核心线程是否空闲)
  • 如果线程池中的线程数已到达或超过核心线程数,那么任务会插入到任务队列中排队等待执行。
  • 如果2中 任务无法插入到队列中,一般是对队列已满,若此时未达到最大线程数,就会启动非核心线程执行这个任务。
  • 如果3中线程数达到最大线程数,那么会拒绝执行任务,即会调用RejectedExecutionHandler的rejectedExecution()通知调用者。

我们看下AsyncTask中线程池的配置:

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    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;
    }

可见THREAD_POOL_EXECUTOR这个线程池的配置如下:

  • 核心线程数,2-4个
  • 最大线程数,CPU核心数量 * 2 + 1
  • 超时时间30s,允许核心线程超时
  • 队列容量128

2.2 线程池的分类

Android中常见的4类线程池,都是直接或间接配置ThreadPoolExecutor实现自己特性的,它们是FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。它们都可以通过工具类Executors获取。

2.2.1 FixedThreadPool

通过Executors的newFixedThreadPool方法获得。固定的核心线程数量,没有非核心线程,空闲时不会被回收,队列长度无限制。因为不会被回收,所以能快速执行外界请求

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

2.2.2 CachedThreadPool

通过Executors的newCachedThreadPool方法获得。核心线程数0,非核心线程数无限制,空闲回收超时时间60s,队列不能插入任务。当所有线程都处于活动状态,就会创建新线程处理任务,否则利用空闲线程处理任务。当整个线程池空闲时 所有线程都会被回收,不占用系统资源。因此,适合执行大量耗时较少的任务

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

2.2.3 ScheduledThreadPool

通过Executors的newScheduledThreadPool方法获得。固定核心线程数,不限制非核心线程数,非核心线程闲置回收超时时间是10ms。一般用于执行定时任务、固定周期的重复任务

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

    private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

2.2.4 SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法获得。仅有1个核心线程,不会回收。可确保所有任务按顺序执行,不用处理线程同步的问题。

    private void testThreadPoolExecutor() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Log.i(TAG, "testThreadPoolExecutor: run begin");
                    Thread.sleep(4000);
                    Log.i(TAG, "testThreadPoolExecutor: run end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
        fixedThreadPool.execute(runnable);

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        cachedThreadPool.execute(runnable);

        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
        scheduledThreadPool.execute(runnable);
        //延迟2秒执行
        scheduledThreadPool.schedule(runnable, 2, TimeUnit.SECONDS);
        //延迟2秒执行,然后以每次 任务开始的时间计时, 1秒后,如果任务是结束的 就立刻执行下一次;如果没有结束,就等它结束后立即执行下一次。
        scheduledThreadPool.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
        //延迟3秒执行,然后以每次任务执行完后的时间计时, 2秒后,执行下一次~
        scheduledThreadPool.scheduleWithFixedDelay(runnable,1,2,TimeUnit.SECONDS);

        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        singleThreadExecutor.execute(runnable);
    }

注意点:scheduledThreadPool使用时注意区分scheduleAtFixedRate、scheduleWithFixedDelay的循环任务的逻辑区别

  • scheduleAtFixedRate,以每次 任务开始的时间计时, period时间后,如果任务是结束的就立刻执行下一次;如果没有结束,就等它结束后立即执行下一次。
  • scheduleWithFixedDelay,以每次任务执行完后的时间计时,period时间后,执行下一次。

并且,这两个方法都是在任务结束后才执行下一次,那么如果某个任务发生异无法执行完,那么整个循环任务就会失效。所以需要给任务添加超时机制(比如给任务加上try-catch-finally,catch住超时异常) 保证任务即使发生异常也可以结束,就可保证循环正常执行了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 胡飞洋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 AsyncTask
    • 1.1.1 使用方法
      • 1.1.2 原理分析:
      • 1.2 HandlerThread
      • 1.3 IntentService
      • 2.1 ThreadPoolExecutor
      • 2.2 线程池的分类
        • 2.2.1 FixedThreadPool
          • 2.2.2 CachedThreadPool
            • 2.2.3 ScheduledThreadPool
              • 2.2.4 SingleThreadExecutor
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档