一、AsyncTask
AsyncTask是一种轻量级的异步处理机制,适用于简单的后台使命,例如网络恳求、文件读写等。AsyncTask能够主动处理线程切换,将成果回调到主线程。
1.1 运用办法
- 创立一个承继自AsyncTask的子类,定义三个泛型参数:Params(传入参数类型)、Progress(进展类型)和Result(回来成果类型)。
- 完结
doInBackground()
办法,履行后台使命。在这个办法中,能够调用publishProgress()
来更新进展。 - 如果需求,能够重写
onPreExecute()
、onProgressUpdate()
和onPostExecute()
办法,别离在使命开端前、进展更新和使命完结后履行。
1.2 技巧
- 避免在AsyncTask中引证Activity或其他可能导致内存走漏的目标。能够运用WeakReference来避免内存走漏。
- 不要在AsyncTask中履行长时刻运转的使命,由于它可能会堵塞线程池中的其他使命。
二、HandlerThread
HandlerThread是一种运用Handler处理音讯行列的线程。它承继自Thread类,内部封装了一个Looper,能够处理来自其他线程的音讯。
2.1 运用办法
- 创立一个HandlerThread实例,并调用
start()
办法发动线程。 - 调用
getLooper()
办法获取HandlerThread的Looper,并用它创立一个Handler实例。 - 运用Handler的
post()
、postDelayed()
或sendMessage()
办法将使命发送到HandlerThread的音讯行列。
2.2 技巧
- 在不再需求HandlerThread时,调用
quit()
或quitSafely()
办法来中止线程。 - 能够运用HandlerThread来处理多个相关使命,以避免频频地创立和毁掉线程。
- 在Android中,
IntentService
和JobIntentService
都是基于Service
组件完结的后台服务。它们的作业原理首要经过创立作业线程来在后台履行使命,以避免堵塞主线程。下面咱们结合Android源码,来看一下它们是怎么完结后台运转的。
三、IntentService和JobIntentService
3.1 IntentService
IntentService
在其内部创立了一个作业线程来履行使命。当你发动IntentService
时,它会创立一个作业线程,并在这个线程中调用onHandleIntent(Intent intent)
办法。你能够在onHandleIntent(Intent intent)
办法中履行耗时操作,而不会堵塞主线程。当一切使命履行完后,IntentService
会主动中止。
它的首要代码如下:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
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);
}
}
在onStart()
办法中,将Intent
封装到Message
中,然后发送到Handler
。Handler
在作业线程中处理Message
,调用onHandleIntent(Intent intent)
办法来履行使命,使命履行完后调用stopSelf(int startId)
办法来中止服务。
3.2 JobIntentService
JobIntentService
的完结办法取决于Android的版别。
-
在Android 7.1及以下版别,
JobIntentService
的行为与IntentService
相同,它在一个独自的线程中处理作业,当一切使命完结后,服务主动中止。 -
在Android 8.0及以上版别,由于后台服务的发动受到了限制,
JobIntentService
运用JobScheduler
来调度使命。JobScheduler
是Android 5.0引入的一种服务,它能够在满足特定条件(如设备充电、设备闲暇等)时履行使命。
它的首要代码如下:
static final class JobServiceEngineImpl extends JobServiceEngine
implements JobIntentService.CompatJobEngine {
final JobIntentService mService;
final Object mLock = new Object();
JobParameters mParams;
JobServiceEngineImpl(JobIntentService service) {
super(service);
mService = service;
}
@Override
public IBinder compatGetBinder() {
return getBinder();
}
@Override
public boolean onStartJob(JobParameters params) {
synchronized (mLock) {
mParams = params;
}
mService.ensureProcessorRunningLocked(false);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
boolean result = mService.doStopCurrentWork();
synchronized (mLock) {
mParams = null;
}
return result;
}
}
在onStartJob(JobParameters params)
办法中,将JobParameters
保存起来,然后发动作业线程来处理使命。在onStopJob(JobParameters params)
办法中,中止当时的作业,并将JobParameters
置为null
。
总的来说,IntentService
和JobIntentService
都是经过在独自的线程中履行使命来完结后台运转的,而JobIntentService
还能够利用JobScheduler
在满足特定条件时履行使命,这使得JobIntentService
在Android 8.0及以上版别中能够更好地习惯体系的后台限制。
四、常见的线程池类型
线程池是一种管理线程的高效办法,能够重用线程,减少线程创立和毁掉的开支。在Android中,能够运用Java规范库中的java.util.concurrent
包中的ThreadPoolExecutor类或Executors工具类来创立线程池。
4.1 常见的线程池类型及其用法
4.1.1 FixedThreadPool(固定巨细线程池)
FixedThreadPool是一个拥有固定数量线程的线程池。这种线程池能够用于履行并发数量有限的使命,例如CPU密集型使命。
用法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
// 履行使命
}
});
4.1.2 CachedThreadPool(缓存线程池)
CachedThreadPool是一个能够依据需求创立新线程的线程池。这种线程池适用于履行大量短时刻使命的场景,例如I/O密集型使命。
用法:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
// 履行使命
}
});
4.1.3 SingleThreadExecutor(单线程线程池)
SingleThreadExecutor是一个只要一个线程的线程池。这种线程池能够用于确保使命按次序履行,例如需求次序处理的使命。
用法:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
// 履行使命
}
});
4.1.4 ScheduledThreadPoolExecutor(定时线程池)
ScheduledThreadPoolExecutor是一个能够履行定时使命或周期性使命的线程池。
用法:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
// 推迟1秒后履行使命
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
// 履行使命
}
}, 1, TimeUnit.SECONDS);
// 推迟1秒后,每隔2秒履行一次使命
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// 履行使命
}
}, 1, 2, TimeUnit.SECONDS);
4.2 技巧
- 依据使命的特色挑选适宜的线程池类型。例如,对于CPU密集型使命,能够运用固定巨细的线程池;对于I/O密集型使命,能够运用缓存线程池。
- 在不再需求线程池时,调用
shutdown()
或shutdownNow()
办法来封闭线程池,释放资源。
五、自定义线程池
ThreadPoolExecutor 是 Java 并发库中的一个类,用于创立和管理自定义线程池。它供给了灵敏的线程池装备选项,适用于各种使命场景。以下是关于 ThreadPoolExecutor 的用法的具体论述。
- 创立 ThreadPoolExecutor
要创立 ThreadPoolExecutor,请运用其结构函数:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 闲暇线程的存活时刻
TimeUnit unit, // 存活时刻的单位
BlockingQueue<Runnable> workQueue, // 作业行列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝战略
);
- 提交使命
运用 execute()
办法提交 Runnable 使命:
executor.execute(new Runnable() {
@Override
public void run() {
// 履行使命
}
});
或许运用 submit()
办法提交 Callable 使命,该办法会回来一个 Future
目标,能够用于获取使命的履行成果:
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() {
// 履行使命并回来成果
return "Hello, ThreadPoolExecutor!";
}
});
- 封闭线程池
在不再需求线程池时,调用 shutdown()
办法来封闭线程池。这将等候一切使命完结后封闭线程池:
executor.shutdown();
如果需求当即封闭线程池,能够调用 shutdownNow()
办法。这将尝试中止一切正在履行的使命,并回来等候履行的使命列表:
List<Runnable> pendingTasks = executor.shutdownNow();
- 获取线程池状况
ThreadPoolExecutor 供给了一些办法来获取线程池的状况,例如:
-
getPoolSize()
:获取线程池中的当时线程数。 -
getActiveCount()
:获取线程池中正在履行使命的线程数。 -
getCompletedTaskCount()
:获取线程池已完结的使命数。 -
getTaskCount()
:获取线程池已接纳的使命总数(包括已完结、正在履行和等候履行的使命)。
示例:
System.out.println("线程池巨细: " executor.getPoolSize());
System.out.println("活泼线程数: " executor.getActiveCount());
System.out.println("已完结使命数: " executor.getCompletedTaskCount());
System.out.println("总使命数: " executor.getTaskCount());
总归,ThreadPoolExecutor 供给了灵敏的线程池装备选项,使得咱们能够依据使命的特色创立适宜的线程池。在运用 ThreadPoolExecutor 时,需求留意合理地装备参数,以及在恰当的机遇封闭线程池,以免形成资源走漏。
六、总结
经过合理地运用AsyncTask、HandlerThread和线程池等子线程技能,能够有效地提高Android应用的功能和响应速度,从而提高用户体验。一起,要留意避免内存走漏、线程堵塞等问题,确保应用的稳定运转。