本篇是多线程系列的第四篇,如果对前三篇感兴趣的也可以去看看。
多线程(一)、基础概念及notify()和wait()的使用
多线程(二)、内置锁 synchronized
多线程(三)、线程池 ThreadPoolExecutor 知识点总结
除了前面的线程池的使用外,在Android中,我们除了通过Thread
创建线程外,还可以通过 AsyncTask
、IntentService
、HandleThread
来创建,线程池前面一篇已经详细介绍了,下面对其他几个方法简单的介绍。
1.1、HandleThread
1.1.1、源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } public HandlerThread(String name, int priority) { super(name); mPriority = priority; } protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } public Looper getLooper() { if (!isAlive()) { return null; } synchronized (this) { while (isAlive() && mLooper == null) { try { 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; } }
可以看到 HandlerThread
继承的是 Thread
,其在内部自己实现了 Looper
,可以单独发送和接收消息,可以实现ui线程到子线程通信和子线程到子线程的通信。
1.1.2、使用
1、创建HandlerThread
并启动
1
2
3
4
5// 创建 HandlerThread 实例对象,参数为自定义线程名字,作为标记 handlerThread = new HandlerThread("HandlerThreadTest"); // 启动 HandlerThread handlerThread.start();
2、创建工作线程,并复写 handleMessage
方法
1
2
3
4
5
6
7
8
9
10
11// 创建工作线程,复写 handleMessage 方法 workHandler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); boolean isMain = Looper.myLooper() == Looper.getMainLooper(); System.out.println("收到消息:what=" + msg.what + ",message=" + (String) msg.obj); System.out.println("IsMainThread=" + isMain + ",currentThread:" + Thread.currentThread()); } };
3、发送消息 (这里模拟在子线程中发送消息)
1
2
3
4
5
6
7
8
9
10
11
12
13
14new Thread(new Runnable() { @Override public void run() { // 使用工作线程向工作线程发送数据。 Message msg = Message.obtain(); msg.what = 1; msg.obj = "测试数据"; workHandler.sendMessage(msg); boolean isMain = Looper.myLooper() == Looper.getMainLooper(); System.out.println("IsMainThread=" + isMain + ",currentThread:" + Thread.currentThread()); } }).start();
4、释放
1
2
3// 释放 mHandlerThread.quitSafely();
运行结果:
可以看到上面的示例实现了在两个子线程之间数据传送。
如果我们将发送消息放在ui线程,即实现了ui线程到子线程的数据通信。
1.2、IntentService
1.2.1、源码
同样的,intentService
源码也不多,这里直接贴出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } public IntentService(String name) { super(); mName = name; } public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; } @Override public void onCreate() { // TODO: It would be nice to have an option to hold a partial wakelock // during processing, and to have a static startService(Context, Intent) // method that would launch the service & hand off a wakelock. super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } @Override public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); } @Override public IBinder onBind(Intent intent) { return null; } @WorkerThread protected abstract void onHandleIntent(Intent intent); }
通过源码,可以看到 IntentService
是一个抽象类,还有一个抽象方法 onHandleIntent
,继承至 Service
1.2.2、使用
新建一个MyIntentService
继承至 IntentService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("IntentService"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate: "); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(@Nullable Intent intent) { boolean isMainThread = Looper.getMainLooper() == Looper.myLooper(); Log.i(TAG, "onHandleIntent: isMainThread=" + isMainThread); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "onHandleIntent: 任务结束"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); } }
2、跟Service
一样,需要在 AndroidManifest.xml
中进行注册
1
2<service android:name=".MyIntentService">
3、启动服务
1
2startService(new Intent(this, MyIntentService.class));
运行结果:
可以看到在MyIntentService
中 onHandleIntent
默认给我们开启了一个子线程来执行耗时操作,且当任务执行结束后自动停止服务,和Service的区别是 使用Service 可以同时执行多个请求,而使用IntentService 只能同时执行一个请求。
1.3、AsyncTask
AsyncTask
也是我们在Android中使用较为频繁的异步通信方法,我们可以通过 AsyncTask
轻松的实现子线程到ui线程的通信,保证了线程安全,减少了我们通过 Thread
+ Handler
这种复杂的组合方法来实现,而且AsyncTask
实现原理也是通过线程池,所以也具有上面线程池的好处。
1.3.1、使用
1
2
3
4public abstract class AsyncTask<Params, Progress, Result>{ // ...... }
首先可以看到 AsyncTask
是一个抽象类,所以,我们在使用的时候需要创建自己的类来实现它,还要实现里面唯一的一个抽象方法。
1
2protected abstract Result doInBackground(Params... params);
可以看到抽象方法有三个泛型参数,分别是.
Params : 开始异步任务执行时传入的参数类型,与
doInBackground()
参数和执行时调用 excute() 参数类型一致。Progress : 异步任务执行过程中,返回下载进度值的类型,与
onProgressUpdate()
参数类型一致。Result : 异步任务执行完成后,返回的结果类型,与
doInBackground()
的返回值类型还有onPostExecute()
参数类型一致
使用 AsyncTask
时,除了必须实现的抽象方法外,一般还有几个方法比较重要,可以根据我们的需求进行重写
- onPreExecute:主线程,执行线程任务前自动调用,通过在这个方法里面进行相应的初始化操作。
- doInBackground:子线程,必须实现的抽象方法,方法里面为工作线程,可以进行耗时操作。
- onProgressUpdate:主线程,任务执行时候,获取进度,通过在
doInBackground
方法中调用publishProgress
来触发 - onPostExecute :主线程,当任务执行结束后自动调用,可进行UI更新。
简单示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48// 新建 MyAsyncTask 实现 抽象类 AsyncTask // Params:Integer // Progress:String // Result:Double public class MyAsyncTask extends android.os.AsyncTask<Integer, String, Double> { @Override protected void onPreExecute() { super.onPreExecute(); System.out.println(TAG + "--onPreExecute"); } // 这里的参数类型为我们自己设置的Params 参数类型 @Override protected Double doInBackground(Integer... integers) { // 模拟耗时操作 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(TAG + "--doInBackground length=" + integers.length); for (Integer i : integers) { System.out.println(TAG + "--doInBackground data=" + i); // 在 doInBackground 调用 publishProgress 触发 onProgressUpdate publishProgress(i + "—更新后的值"); } // 这里模拟返回结果,参数类型为我们设置的 Double return 2.2; } // 这里的参数类型为我们自己设置的String类型 (Progress) @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); for (String data : values) { System.out.println(TAG + "--onProgressUpdate date=" + data); } } // 任务执行结束后自动触发,参数类型为我们自己设置的Result 参数类型 @Override protected void onPostExecute(Double aDouble) { super.onPostExecute(aDouble); System.out.println(TAG + "--onPostExecute aDouble=" + aDouble); } }
调用 MyAsyncTask
:
通过 execute
方法调用,需要在主线程里面执行,传入参数需要和 doInBackground
参数一致,及 Params
设置的类型。
只能调用一次,如果调用两次
execute
方法,会抛异常Caused by: java.lang.IllegalStateException: Cannot execute task: the task is already running.
1
2
3MyAsyncTask myAsyncTask = new MyAsyncTask(); myAsyncTask.execute(100,101,102);
结果:
1.3.2、源码分析
我们深入 AsyncTask
大致看看它是怎么实现的,首先从 构造方法入手
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); // 通过Callable创建一个任务 mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 从 doInBackground 中获取 result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { // 任务执行结束,将结果 发送到 postResult(result); } // 返回结果 return result; } }; // 将任务传给 FutureTask ,复写其 done 方法 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); } } }; } // WorkerRunnable private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
我们看到构造方法中,先创建了一个Callable
的任务,在 多线程(一)、基础概念及notify()和wait()的使用 我们介绍了通过 Callable
来创建线程,可以在线程结束后获取结果,我们也看到在 任务里面通过 result = doInBackground(mParams)
获取到结果。任务创建后,将其放入到 FutureTask
中,这是 Callable
线程创建的标准用法。
看完构造方法,我们再来看调用 execute
方法执行的时候,它又做了啥。
1
2
3
4
5@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
这里没啥信息,直接调用了executeOnExecutor
方法,传入了 sDefaultExecutor
和我们设置的参数,再看 executeOnExecutor
方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public 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 方法 onPreExecute(); mWorker.mParams = params; // 执行了我们在构造方法里面创建的mFuture exec.execute(mFuture); return this; }
这里面我们还是看到很有用的信息,首先调用了 onPreExecute
方法,这也是我们在执行 AsyncTask
方法的时候,调用的第一个方法,用来进行一些初始化操作,我们的任务通过 exec.execute(mFuture)
进行执行,看看我们传入的 sDefaultExecutor
是个啥。
最终创建了 SerialExecutor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private 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); } } }
内部声明了一个双端队列ArrayDeque
类型的mTasks
(双端队列中offer方法表示从队列尾插入,poll()表示从队列头获取元素)。
这里通过 mTasks.offer
将我们的任务不断的放入阻塞队列中,再通过 mTasks.poll()
拿出任务,最终通过 THREAD_POOL_EXECUTOR
来执行。
再看 THREAD_POOL_EXECUTOR
又是啥?
1
2
3
4
5
6
7
8static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), sThreadFactory); threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy); THREAD_POOL_EXECUTOR = threadPoolExecutor; }
我们前面说了,AsyncTask
内部是通过线程池来执行的,看这里应该就清楚了,任务的执行,实质是通过创建的 threadPoolExecutor
线程池,来执行任务。按照前面的老规矩,看看具体参数。
参数说明:
1
2
3
4private static final int CORE_POOL_SIZE = 1; private static final int MAXIMUM_POOL_SIZE = 20; private static final int KEEP_ALIVE_SECONDS = 3;
int corePoolSize: 1
int maximumPoolSize: 20
long keepAliveTime:3
TimeUnit unit:TimeUnit.SECONDS
BlockingQueue workQueue:new SynchronousQueue()
1个核心线程,非核心线程数目为20,使用 SynchronousQueue
阻塞队列。
这里源码是查看的API 29 ,不同的版本有区别。
看到了任务的执行,那么AsyncTask是怎么实现子线程到主线程的数据通信的呢?
postResult:
1
2
3
4
5
6
7
8private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
前面构造中,我们看到通过 doInBackground
返回的结果,通过 postResult
方法传递出去了,而在 postResult
里面就是通过Handler,来将数据从子线程传到了主线程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private 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; } } }
我们再看看publishProgress
1
2
3
4
5
6
7protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
其本质,也是通过 Handler
来实现子线程到主线程的数据通信。
总结:所以,AsyncTask 本质是通过线程池来执行任务,并且封装了 Handler
来实现子线程到ui线程的数据传输。
优点:AsyncTask 是一个轻量级的异步任务处理类,轻量级体现在,使用方便、代码简洁上,而且整个异步任务的过程可以通过cancel()进行控制。
缺点:不适用于处理长时间的异步任务,一般这个异步任务的过程最好控制在几秒以内,如果是长时间的异步任务就需要考虑多线程的控制问题;当处理多个异步任务时,UI更新变得困难。
二、总结
多线程部分一共四篇,这篇收了个尾,后面也会继续对Android其他知识点进行总结,Android进阶系列也会一直写下去,如果文中有错误的地方,欢迎大佬们批评指点。
最后
以上就是笨笨泥猴桃最近收集整理的关于多线程(四)、Android多线程使用及AsyncTask源码分析的全部内容,更多相关多线程(四)、Android多线程使用及AsyncTask源码分析内容请搜索靠谱客的其他文章。
发表评论 取消回复