线程
在java中实现线程的方式:
- 继承Thread类
- 实现Runable接口。
main方法其实也是一个线程。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。
-
对比
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立 -
yield()方法
Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
-
join()方法
保证当前线程停止执行,直到该线程所加入的线程完成为止,当前线程方可继续执行。然而,如果它加入的线程没有存活,则当前线程不需要停止。
关于进程和线程的区别请参考进程和线程的深入理解
AsyncTask
-
内部由两个线程池和一个Handler组成。
- SerialExecutor:用于任务的排队,一次执行一个。
- ThreadPoolExecutor:用于真正的执行任务。
- InternalHandler:用于发送结果数据从子线程到主线程。
-
执行流程:
构造方法中实例化WorkerRunnable和FutureTask对象。
WorkerRunnable将Params参数封装,并将自己封装在FutureTask中,一旦FutureTask执行run方法时,会去调用WorkRunnable的call方法并返回Result值。call方法中就执行了AsyncTask的doInBackground方法。并调用postResult方法将结果发送出去。mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
那么FutureTask是什么时候执行的?
FutureTask充当了Runnable的作用,交给SerialExecutor的execute方法执行。FutureTask是一个并发类,可以中途取消的用于异步计算的类。SerialExecutor的execute方法首先把FutureTask插入到mTasks任务队列中,如果没有活动的任务,则执行下一个。当一个任务执行完成,会继续调用scheduleNext方法执行下一个,直到所有任务都被执行。
THREAD_POOL_EXECUTOR.execute(mActive);才是真正执行任务的方法。使用的是ThreadPoolExecutor线程池。
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { //将FutureTask插入到mTasks任务队列中 mTasks.offer(new Runnable() { public void run() { try { // 执行FutureTask的run方法,进而执行call方法 r.run(); } finally { // 串行执行下一个任务 scheduleNext(); } } }); //没有正在活动的任务,执行下一个AsyncTask。 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
-
注意:
- AsyncTask对象必须在主线程中创建
- execute必须在主线程中调用
- 一个AsyncTask只能调用一次execute方法,
HandlerThread
继承了Thread类,本质还是线程。但是可以直接使用Handler的Thread。在run方法中通过Looper.prepare创建消息队列,并开启消息循环。使得可以再次线程中创建Handler。
同时,它还解决了一个Looper与Handler的同步问题。可以保证根据当前线程的Looper创建Handler时,Looper对象的获取不为空。
参考《深入理解Android 卷I》159页
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
由于loop开启了无限循环,因此可以通过quit或者quitSafely方法终止线程执行。
典型应用场景就是在IntentService中。
@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.服务开启后,工作线程会依次处理每个Intent,任务执行完毕后会自动关闭。
相对于线程而言,IntentService更适合执行一些高优先级的后台任务。
@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);
}
线程池
- 优点
- 重用线程池中的线程,避免因为线程的创建和销毁带来的性能开销。
- 有效控制线程的最大并发数,避免因大量的线程之间互相抢占系统资源而导致的阻塞 。
- 能够对线程进行简单的管理,并提供定时执行和执行循环间隔执行等功能
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { }
-
变量
- corePoolSize: 核心线程数
- maximumPoolSize: 最大线程数
- workQueue:任务队列,提交的Runnable对象存储在这里。
- keepAliveTime: 非核心线程存活时间
- unit:keepAliveTime的时间单位。
- threadFactory:为线程池提供新线程的工厂。
- handler:异常处理策略。
-
规则
- 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
- 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
- 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
- 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。