sunxin's Studio.

Android的线程和线程池知多少

字数统计: 867阅读时长: 3 min
2018/10/09 Share

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
CATALOG
  1. 1. Android的线程和线程池
    1. 1.1. Android中的线程形态
      1. 1.1.1. AsyncTask
        1. 1.1.1.1. AsyncTask的工作原理
      2. 1.1.2. HandlerThread
      3. 1.1.3. IntentService
    2. 1.2. Android中的线程池
      1. 1.2.1. 线程池的分类