一、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中,IntentServiceJobIntentService都是基于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中,然后发送到HandlerHandler在作业线程中处理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

总的来说,IntentServiceJobIntentService都是经过在独自的线程中履行使命来完结后台运转的,而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 的用法的具体论述。

  1. 创立 ThreadPoolExecutor

要创立 ThreadPoolExecutor,请运用其结构函数:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        int corePoolSize, // 核心线程数
        int maximumPoolSize, // 最大线程数
        long keepAliveTime, // 闲暇线程的存活时刻
        TimeUnit unit, // 存活时刻的单位
        BlockingQueue<Runnable> workQueue, // 作业行列
        ThreadFactory threadFactory, // 线程工厂
        RejectedExecutionHandler handler // 拒绝战略
);
  1. 提交使命

运用 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!";
    }
});
  1. 封闭线程池

在不再需求线程池时,调用 shutdown() 办法来封闭线程池。这将等候一切使命完结后封闭线程池:

executor.shutdown();

如果需求当即封闭线程池,能够调用 shutdownNow() 办法。这将尝试中止一切正在履行的使命,并回来等候履行的使命列表:

List<Runnable> pendingTasks = executor.shutdownNow();
  1. 获取线程池状况

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应用的功能和响应速度,从而提高用户体验。一起,要留意避免内存走漏、线程堵塞等问题,确保应用的稳定运转。