# 多线程优化

## 多线程基础

[多线程基础](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/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiaojianchen.gitbook.io/performance-optimization/duo-xian-cheng-you-hua.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
