一、概述
Android 的线程分主线程和子线程,主线程主要处理界面相关的事情,而子线程往往用于执行耗时操作。Android 中扮演子线程角色的有:AsyncTask、IntentService、HandlerThread。AsyncTask 封装了线程池和 Handler,主要用于在子线程中更新UI。 HandlerThread 是一种具有消息循环的线程,在它的内部可以使用 Handler。IntentService 是一个 Service,系统对其进行了封装使其可以方便地执行后台任务,执行完任务后自动调用 onDestroy()
退出。它是一个 Service,因而在执行后台任务的时候不容易被系统杀死。
二、AsyncTask
AsyncTask 是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后在主线程中回调执行的进度以及最终结果,从而更新 UI。其实,AsyncTask 内部封装了 Thread 和 Handler。
ASyncTask 是一个抽象类。
public abstract class AsyncTask<Params,Progress,Result>
主要有 4 个核心的方法:
-
onPreExecute():在主线程执行,在异步任务执行之前的准备工作,比如:提示 Loading
-
doInBackground(Params... params):在线程池中执行,此方法用于执行异步任务,params 表示异步任务的输入参数。
-
onProgressUpdated(Progress... value):在主线层中执行,当后台任务的进度发生改变时此方法被调用。
-
onPostExecute(Result result):在主线程执行,在异步任务执行完成后回调此方法。
-
onCancelled():在主线程执行,当异步任务被取消时会回调此方法。
举个栗子:
class DownloadTask extends AsyncTask<URL,Integer,Long>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Long doInBackground(URL... urls) {
return null;
}
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
new DownloadTask().execute(url1,url2,url3);
划重点来啦 !!!
-
1. AsyncTask 的类必须在主线程中加载,不过这个在 Android 4.1 及以上版本已经在 ActivityThread 中初始化了。
-
2. AsyncTask 对象必须在主线程中创建。
-
3.
execute()
必须在 UI 线程中调用。 -
4. 不要在程序中直接调用
onPreExcute()
、doInBackground()
、onPostExecute()
和onProgressUpdate()
。 -
5. 一个 AsyncTask 对象只能执行一次,即只能调用一次
execute()
,否则会报运行异常。 -
6. 可以通过
executeOnExecutor()
来并行执行任务。
三、HandlerThread
HandlerThread 继承 Thread,它封装有 Looper 和 MessageQueue,可以绑定 Handler,从而实现线程间通信/异步消息处理机制。
举个栗子
/**
* 使用 HandlerThread
*/
public class HandlerThreadActivity extends AppCompatActivity {
private TextView mTvServiceInfo;
private HandlerThread mCheckMsgThread;
//HandlerThread 的 handler
private Handler mCheckMsgHandler;
private boolean isUpdateInfo;
private static final int MSG_UPDATE_INFO = 0x110;
//与UI线程管理的handler
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
//创建后台线程
initBackThread();
mTvServiceInfo = findViewById(R.id.id_textview);
}
@Override
protected void onResume() {
super.onResume();
//开始查询
isUpdateInfo = true;
mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause() {
super.onPause();
//停止查询
isUpdateInfo = false;
mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
}
private void initBackThread() {
mCheckMsgThread = new HandlerThread("check-message-coming");
mCheckMsgThread.start();
//绑定 HandlerThread 的 Looper
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
checkForUpdate();
if (isUpdateInfo) {
//循环执行 HandlerThread Handler 的 handleMessage()
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
}
}
};
}
/**
* 模拟从服务器解析数据
*/
private void checkForUpdate() {
try {
//模拟耗时
Thread.sleep(1000);
//切换回主线程
mHandler.post(new Runnable() {
@Override
public void run() {
String result = "实时更新中,当前大盘指数:<font color='red'>%d</font>";
result = String.format(result, (int) (Math.random() * 3000 + 1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//释放资源
mCheckMsgThread.quit();
}
}
这个栗子里面通过 HandlerThread 线程的 Handler 来通知 UI 线程的 Handler 来更新 UI,同时在 handleMessage() 方法中循环执行 HandlerThread 的方法,这个也是一种定时循环执行任务的方法。
源码分析:
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
//内部有一个 Handler 成员变量
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
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;
}
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
我们仔细看看 run()
,这里面调用了 Looper.prepare()
,Loop.loop()
。Looper.prepare()
中创建了一个 Looper 对象,并且把该对象放到了该线程范围内的变量中(sThreadLocal),在 Looper 对象的构造过程中,初始化了一个 MessageQueue ,作为该 Looper 对象成员变量。Looper.loop()
就不断地循环从 MessageQueue 中取消息处理了,当没有消息的时候会阻塞,有消息的到来的时候会唤醒。
如果我们不想自己初始化 HandlerThread 的 Handler 对象,可以直接使用 HandlerThread 里面的 Handler,使用的时候就只能用 post(Runnable r)
,因为 HandlerThread 的 Handler 没有派生子类,只能使用 Message.callback 来执行任务。
四、IntentService
IntentService 是一种特殊的 Service,它继承了 Service,并且是一个抽象类,子类必须实现 onHandleIntent()
才可以使用。IntentService 可用于执行后台任务,我们可以通过 startService(Intent)
来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。而且由于它是 Service,比单纯的后台线程优先级高,不容易被系统杀死。
优点:
-
1.不需要自己去 new Thread
-
2.不需要考虑在什么时候关闭该 Service
举个栗子
使用 IntentService 上传照片
public class UploadImgService extends IntentService {
private static final String ACTION_UPLOAD_IMG = "com.zhy.blogcodes.intentservice.action.UPLOAD_IMAGE";
public static final String EXTRA_IMG_PATH = "com.zhy.blogcodes.intentservice.extra.IMG_PATH";
/**
* 外部调用开启任务
* @param context
* @param path
*/
public static void startUploadImg(Context context, String path) {
Intent intent = new Intent(context, UploadImgService.class);
intent.setAction(ACTION_UPLOAD_IMG);
intent.putExtra(EXTRA_IMG_PATH, path);
context.startService(intent);
}
public UploadImgService() {
super("UploadImgService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_UPLOAD_IMG.equals(action)) {
final String path = intent.getStringExtra(EXTRA_IMG_PATH);
handleUploadImg(path);
}
}
}
private void handleUploadImg(String path) {
try {
//模拟上传耗时
Thread.sleep(3000);
Intent intent = new Intent(MainActivity.UPLOAD_RESULT);
intent.putExtra(EXTRA_IMG_PATH, path);
//通过广播通知 UI 线程
sendBroadcast(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG","onCreate");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG","onBind");
return null;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("TAG","onSatrtCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Log.e("TAG","onSatrt");
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("TAG","onDestroy");
}
}
上面的代码主要就是继承IntentService,然后复写onHandleIntent方法,根据传入的intent来选择具体的操作。
运行 Log:
04-16 07:56:59.894 19936-19936/com.innovator.intentservicetest E/TAG: onCreate
onSatrtCommand
onSatrt
04-16 07:57:00.500 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:00.774 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:01.788 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:01.965 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
通过 startUploadImg(Context context, String path)
来创建多个任务,可以看到 onCreate()
只调用了一次,onStartCommand()
和 onStart()
会回调多次。
划重点啦 !!!
源码解析:
package android.app;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
public 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() {
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;
}
protected abstract void onHandleIntent(Intent intent);
}
可以看到它在 onCreate()
里面初始化了一个 HandlerThread,同时实例化了一个绑定该 HandlerThread 的 Handler。当任务开始的时候,会回调 onStartCommand()
,即回调 onStart()
,在 onStart()
中可以看到这个 Handler 发送了一条消息给自己,于是就会调用自己的处理方法,最后调用 onHandleIntent((Intent)msg.obj)
方法,所以我们在使用 IntentService 的时候需要重写 onHandleIntent((Intent)msg.obj)
。
而且,由于 HandlerThread 是串行执行任务的,所以 IntentService 也是串行执行任务的,执行完成后会调用 stopSelf(msg.arg1);
判断是否销毁该 Service(stopSelf(msg.arg1);
会等待所有消息都处理完毕才会终止服务)。所以当任务完成,销毁 Service 回调 onDestory()
时,源码里面会释放了我们的 Looper: mServiceLooper.quit()
。
五、线程池
使用线程池有几个好处:
-
1.重用线程池的线程,避免为线程的创建和销毁所带来的性能开销
-
2.能有效控制线程池的最大并发数,避免大量线程之间因互相抢占资源而导致的阻塞现象
-
3.能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。
5.1 ThreadPoolExecutor
ThreadPoolExecutor 是线程池的真正实现,它的构造方法为:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
-
corePoolSize:线程池的核心线程数,默认情况下,核心线程会在线程池一直存活,即使它们处于闲置的状态。如果将 ThreadPoolExecutor 的
allowCoreThreadTimeOut
属性为 true,那么闲置的核心线程在等待新任务到来的时候会有超时策略,这个时间间隔超过keepAliveTime
后,核心线程也会被终止。 -
maximumPoolSize:线程池所能容纳的最大线程数。当活动线程数达到这个数值后,后续的新任务会被阻塞。
-
keepAliveTime:非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。
-
unit:超时时长单位:毫秒,秒,分
-
workQueue:线程池的任务队列,通过线程池的
execute()
提交的 Runnable 对象就存储在这个队列中。 -
threadFactory:线程工厂,为线程池提供创造新线程的功能。
ThreadPoolExecutor 执行任务时的规则:
-
1.如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务
-
2.如果线程池中的线程数量已经达到或者超过核心线程数量,那么任务就会被插入到任务队列中排队等待执行
-
3.如果步骤2中的任务无法插到任务队列,这往往是由于任务队列已满,这时如果线程数量未达到线程池的最大值,那么就会立刻启动一个非核心线程来执行任务。
-
4.如果步骤3中线程数量已经达到线程池规定的最大值,那么就会拒绝执行这项任务,ThreadPoolExecutor 就会调用 RejectedExecutionHandler 的
rejectExecution()
来通知调用方。
5.2 线程池分类
-
1.FixedThreadPool:一种线程数量固定的线程池,核心线程数就是线程池能容纳的最大线程数。所以当线程处于空闲状态时,它们并不会回收,除非线程池被关闭了。当所有线程都处于活动状态时,新任务都会处于等待状态,直到有空闲的线程。因为 FixedThreadPool 只有核心线程并且这些核心线程不会被回收,这就意味着它能更加快速地响应外界的请求。FixedThreadPool 的任务队列没有大小限制。
构造方法:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
使用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
fixedThreadPool.execute(Runnable r);
-
CachedThreadPool:一种线程数量不定的线程池,只有非核心线程,并且最大线程数为 Interger.MAX_VALUE。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理任务,否则就会利用空闲线程来处理新任务。线程池中的空闲线程都有超时机制,超时时长为 60s,超过 60s 就会被回收。它比较适合执行大量的耗时较少的任务。
构造方法:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
使用方法:
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
cacheThreadPool.execute(Runnable r);
-
ScheduledThreadPool:核心线程数量固定,线程池能容纳的最大线程数没有限制,并且当非核心线程闲置时会被立即回收。主要用于执行定时任务和具有固定周期的重复任务。
构造方法:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
使用方法:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
//延迟2秒后执行该任务
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
}
}, 2, TimeUnit.SECONDS);
//延迟1秒后,每隔2秒执行一次该任务
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
}
}, 1, 2, TimeUnit.SECONDS);
-
SingleThreadExecutor:这类线程池内部只有一个核心线程,它确保所有任务都在同一个线程中按顺序执行。意义就是统一所有外界的任务到同一线程中,使得这些任务之间不需要处理线程同步的问题。
构造方法:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
使用方法:
ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();
//延迟1秒后,每隔2秒执行一次该任务
singleThreadScheduledPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
Log.v("zxy", "线程:" + threadName + ",正在执行");
}
},1,2,TimeUnit.SECONDS);
singleThreadScheduledPool.execute(Runnable r);
网友评论