Sunxin'Blog

Android的线程和线程池知多少

Android的线程和线程池

线程角色

  • AsyncTask (底层用到线程池,封装了线程池和Handler)
  • IntentService (底层直接使用线程,服务,后台线程,不容易被杀)
  • HandlerThread (底层直接使用线程,具有消息循环的线程)

Android中的线程形态

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
/**
* 输入参数 URL
* 后台任务的进程参数 Integer
* 后台任务的返回结果 Long
*/
private class DownAsyncTask extends AsyncTask<URL, Integer, Long> {

/**
* 主线程中执行,异步任务执行之前调用,做一些准备工作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}

/**
* 在线程池中执行,执行异步任务.通过publishProgress来更新任务执行进度
*
* @param urls
* @return 返回结果给#onPostExecute
*/
@Override
protected Long doInBackground(URL... urls) {
return null;
}

/**
* 主线程中执行,当后台任务执行发生改变时调用
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}

/**
* 主线程中执行,异步任务执行之后调用
* @param aLong
*/
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
}
}
//执行异步任务
new DownAsyncTask().execute();

AsyncTask在使用中的限制条件

  • AsyncTask类必须在主线程中加载,对戏那个必须在主线程中创建
  • execute方法必须在UI线程中调用
  • 不要在程序中直接调用 onPreExecute(),onPostExecute(),doInBackground和onProgressUpdate()方法
  • 一个AsyncTask对象只能执行一次,即只能调用一次execute方法。否则会报出异常

AsyncTask的工作原理

HandlerThread

继承了Thread,它是一种可以使用Handler的Thread,使用Looper.prepare()来创建消息队列,使用Looper.loop()来开启消息循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

IntentService

特殊的Service,是一个抽象类,可用于执行后台耗时的任务,优先级比单纯的线程要高很多,不容易被系统杀死。封装了HandlerThread和Handler。

1
2
3
4
5
6
7
8
9
10
11
12
13
@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);
}

Android中的线程池

线程池的好处

  • 重用池中的线程,避免线程创建和销毁的性能开销
  • 能有效控制线程池的最大并发数,避免大量的线程之间因为仙湖抢占资源而导致的阻塞现象
  • 能够对线程进行简单的管理

手动创建线程池

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
/**
* cpu核心数
*/
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
/**
* 线程池的核心线程数,默认核心线程会在线程池中一直存活
*/
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);

@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ThreadUtil #" + mCount.getAndIncrement());
}
};

/**
* 线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中
*/
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);

private static Executor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
sPoolWorkQueue,
sThreadFactory);

线程池的分类

  1. FixedThreadPool
  2. CachedThreadPool
  3. ScheduledThreadPool
  4. SingleThreadExecutor
-------------本文结束感谢您的阅读-------------

本文标题:Android的线程和线程池知多少

文章作者:Sun xin

发布时间:2018年10月09日 - 09:10

最后更新:2018年10月09日 - 09:10

原始链接:http://sunxin.tech/2018/10/09/Android的线程和线程池知多少/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。