> For the complete documentation index, see [llms.txt](https://xiaojianchen.gitbook.io/performance-optimization/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xiaojianchen.gitbook.io/performance-optimization/duo-xian-cheng-you-hua.md).

# 多线程优化

## 多线程基础

[多线程基础](https://xiaojianchen.gitbooks.io/java-foundation/content/多线程基础.html)

## AsyncTask

执行流程

new AsyncTask()

```java
public AsyncTask() {
        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);
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
```

会初始化一个Callable和一个FutureTask，当然Callable是要被传到FutureTask的构造方法中去的，最终线程池执行的FutureTask，这两个都是成员变量。

在Callable中可以看到：Result result = doInBackground(mParams); 然后在FutureTask中它有一个执行完成的回调方法done()

之所以用FutureTask就是因为它是负责执行多线程可以返回执行结果的。

然后：

```java
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
```

在这里面，它就是把执行的结果给发到主线程，里面有当前AsyncTask引用和result对象。

```java
protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
```

这个是因为在doBackground中去调用publishProgress（Progress... values），然后可以在主线程中接收到它的处理逻辑。

```java
private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
```

所有任务都是最后由它来分发执行的。

最后关键的来了，最后肯定是要调用执行的

```java
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }
```

重点看下：

```java
exec.execute(mFuture);
```

我们看下sDefaultExecutor是个什么东西

```java
private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
```

也就是说exec.execute(mFuture);这句话会调用SerialExecutor的方法，每次调用execute都会把futureTask给加进去，然后放到一个双端队列里面，如果当前没有执行的Runnable就从队列中取出一个任务去执行，如果有任务的话，那么就只是先单纯的加到队列里，并不会执行。因为每次执行完一个Runnable后，它有一个finally方法，最后一次会再次调用scheduleNext方法，然后再从队列中去取出一个任务去执行，当然前提是队列不能为空，所以，它的逻辑是其实是执行一个任务结束后，然后就去队列里去取任务，如果有就放到线程池里去执行，就是这么简单。所以它是串行的。它是通过先把任务缓存到一个队列里，然后执行完一个就从队列中取出一个放到线程池中去执行，也就是说，队列里有多个任务，但是，线程池始终只有一个任务。

不过线程的无界队列 new LinkedBlockingQueue(128)这个128有点让人恍惚，其实它是指如果你配置成多线程并行的情况下，缓冲队列最多有128个，否则就执行Reject策略(默认是AbortPolicy)。

我们再来看下配置线程池的相关代码

```java
public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
```

CORE\_POOL\_SIZE 核心线程数 MAXIMUM\_POOL\_SIZE 最大线程数量 KEEP\_ALIVE 1s闲置回收 TimeUnit.SECONDS 时间单位 sPoolWorkQueue 异步任务队列 sThreadFactory 线程工厂

![](https://lh3.googleusercontent.com/-qqgO2iTFVhU/WMkMmUQ26tI/AAAAAAAAEG4/R3Fm4pZIPCA/I/WechatIMG1.jpeg)\
首先你要明白，这个128的限制是指你用executeOnExecutor(Executor exec,Params... params)时，并行才会用到这个128的队列，也就是说它是一个有容量限制的无界队列(故意指定的容量大小)。

关于线程池，先会把CORE\_POOL\_SIZE这个填满，填满之后，再往缓存队列里放，缓存队列也满了，就增加线程，直到增加到MAXIMUM\_POOL\_SIZE，然后如果再有新的任务，那么 就只能执行拒绝策略了。

如果你自己配置一个无界队列，那么 任务就随便放了直到把系统干爆为止。

```java
private void startDownload(){
        for (int i = 0; i < 200; i++) {
            new DownloadTask().execute();
        }
    }

    private AtomicInteger mAtomicInteger = new AtomicInteger(0);

    class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(mAtomicInteger.incrementAndGet());
            return true;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
        }

        @Override
        protected void onPostExecute(Boolean result) {
        }
    }
```

上面的代码是每隔1s打印一次，你一次new出来200个也不是说都把放到线程池中的BlockingQueue中，而是放到Executor中的ArrayDeque这个是会不断扩容的队列，明白了吧。

AsyncTask有什么缺点：

1. 内存泄露 — 这是因为匿名内部类持有外部类的引用，所以如果子线程没有执行完毕，
2. 线程池容量不够抛出异常。这个异常其实基本不会出现，因为默认情况下是串行的，而且如果你要自定义线程池的话，可以设置一个更大的BlockingQueue啊。所以这点基本不存在。

[Android AsyncTask完全解析，带你从源码的角度彻底理解](http://blog.csdn.net/guolin_blog/article/details/11711405)

## HandlerThread

HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.

```java
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private HandlerThread myHandlerThread ;
    private Handler handler ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建一个线程,线程名字：handler-thread
        myHandlerThread = new HandlerThread( "handler-thread") ;
        //开启一个线程
        myHandlerThread.start();
        //在这个线程中创建一个handler对象
        handler = new Handler( myHandlerThread.getLooper() ){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //这个方法是运行在 handler-thread 线程中的 ，可以执行耗时操作
                Log.d( "handler " , "消息： " + msg.what + "  线程： " + Thread.currentThread().getName()  ) ;

            }
        };

        //在主线程给handler发送消息
        handler.sendEmptyMessage( 1 ) ;

        new Thread(new Runnable() {
            @Override
            public void run() {
             //在子线程给handler发送数据
             handler.sendEmptyMessage( 2 ) ;
            }
        }).start() ;

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        //释放资源
        myHandlerThread.quit() ;
    }
}
```

```java
/com.app D/handler: 消息： 1  线程： handler-thread
/com.app D/handler: 消息： 2  线程： handler-thread
```

HandlerThread的特点:

* **HandlerThread将loop转到子线程中处理，说白了就是将分担MainLooper的工作量，降低了主线程的压力，使主界面更流畅**。
* **开启一个线程起到多个线程的作用。处理任务是串行执行，按消息发送顺序进行处理。HandlerThread本质是一个线程，在线程内部，代码是串行处理的**。
* **但是由于每一个任务都将以队列的方式逐个被执行到，一旦队列中有某个任务执行时间过长，那么就会导致后续的任务都会被延迟处理**。
* **HandlerThread拥有自己的消息队列，它不会干扰或阻塞UI线程**。
* 对于网络IO操作，HandlerThread并不适合，因为它只有一个线程，还得排队一个一个等着。

## IntentService

IntentService内部会创建一个HandlerThread，onHandleIntent在HandlerThread线程中执行

IntentService源码：

```java
      @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);
    }

    @Override
    public void onStart(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);
        }
    }

    protected abstract void onHandleIntent(Intent intent);
```

看明白了吧，在onCreate中去初始化HandlerThread和用HandlerThread的Looper初始化的Handler，在onStart中发送消息，在handlerMessage中去调用onHandleIntent，然后我们重写onHandleIntent方法即可。

IntentService(本质：Service+HandlerThread+Intent) startService 至少要有一个空的构造方法

优点

1. 提高子线程的优先级
2. 减轻主线程的压力

它有一个很大的缺点就是，**它无法直接和主线程进行通信，其实很多业务是后台做完请求之后要在UI上更新，其实它无法实现，虽然可以用消息机制通信**。

## Loader

在 Android 配备的几大异步利器中，Loader 是3.0之后才出现的，主要为了方便在 Activity 和 Fragment 中异步加载数据。它有如下的特点：

* 每个Activity 和 Fragment 都可以使用 (3.0之前可以使用 support-lib)
* 拥有异步加载数据的功能
* 监视数据源，如果数据发生变化了，会自动传回更新后的结果
* 如果被重新创建(比如屏幕选装)了会自动连接到上次的Cursor，这样不需要重新查询数据

上面说过了，**Android提供了很多后台任务的机制，不过除了AsyncTask，无法把后台执行的结果给调用者(当然FutureTask可以，AsyncTask也是这样做的)，还有一个就是Loader可以在后台加载数据，然后和调用者通信。**

Loader保证子线程与Activity或者Fragment的生命周期一致 Activity和Fragment自带LoaderManager

优点： 1.方便 2.Activity或者Fragment的生命周期一致 3.数据缓存与更新通知

**Activity中启动子线程的缺点**

1. **内存泄露**
2. **无效的更新UI**

```java
import android.app.Activity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.CallLog;
import android.util.Log;
import android.widget.ListView;


public class MainActivity extends Activity {

    private static final String TAG = "jason";
    // 查询指定的条目
    private static final String[] CALLLOG_PROJECTION = new String[] { CallLog.Calls._ID, CallLog.Calls.NUMBER,
            CallLog.Calls.CACHED_NAME, CallLog.Calls.TYPE, CallLog.Calls.DATE };
    private ListView mListView;
    private MyLoaderCallback mLoaderCallback = new MyLoaderCallback();
    private MyCursorAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.lv_list);

        mAdapter = new MyCursorAdapter(MainActivity.this, null);
        mListView.setAdapter(mAdapter);

        //执行Loader的回调
        getLoaderManager().initLoader(0, null, mLoaderCallback);
    }


    private class MyLoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {

        //创建Loader
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            //加载的过程在子线程中进行
            CursorLoader loader = new CursorLoader(MainActivity.this, CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION,
                    null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
            Log.d(TAG, "onCreateLoader");
            return loader;
        }

        //Loader检测底层数据，当检测到改变时，自动执行新的载入获取最新数据
        //Activity/Fragment所需要做的就是初始化Loader，并且对任何反馈回来的数据进行响应。
        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            if (data == null)
                return;
            mAdapter.swapCursor(data);
            Log.d(TAG, "onLoadFinished data count = " + data.getCount());
        }

        //OnDestroy，自动停止load
        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            Log.d(TAG, "onLoaderReset");
            mAdapter.swapCursor(null);
        }
    }

}
```

**其实Loader后台的执行是靠AsyncTask**。

[Android之Loader介绍](http://wangkuiwu.github.io/2014/06/25/Loader/)
