1.主线程和子线程
主线程就是主指UI线程,然而在android系统中一般不能在UI线程中进行耗时比较大的操作,这个时候就需要引进子线程去处理,android里有几个特殊的线程封装,分别是
AsyncTask ThreadHandler IntentService
2.AsyncTask
使用场景:
AsyncTask是轻量级的异步任务类,他可以在线程池中执行异步任务,然后把执行结果和结果传递给主线并在主线程中更新ui.并不建议用AsyncTask来处理比较耗时的任务 。
在新线程中进行耗时操作,当任务完成后通过Handler向主线程发送Message,这样主线程的Handler在收到该Message之后就可以进行更新UI的操作。上述场景中需要分别在Thread和Handler中编写代码逻辑,为了使得代码更加统一,我们可以使用AsyncTask类。
AsyncTask的缺陷:
1.生命周期
关于AsyncTask存在一个这样广泛的误解,很多人认为一个在Activity中的AsyncTask会随着Activity的销毁而销毁。然后事实并非如此。AsyncTask会一直执行doInBackground()方法直到方法执行结束。一旦上述方法结束,会依据情况进行不同的操作。
•如果cancel(boolean)调用了,则执行onCancelled(Result)方法
•如果cancel(boolean)没有调用,则执行onPostExecute(Result)方法
AsyncTask的cancel方法需要一个布尔值的参数,参数名为mayInterruptIfRunning,意思是如果正在执行是否可以打断,如果这个值设置为true,表示这个任务可以被打断,否则,正在执行的程序会继续执行直到完成。如果在doInBackground()方法中有一个循环操作,我们应该在循环中使用isCancelled()来判断,如果返回为true,我们应该避免执行后续无用的循环操作。
总之,我们使用AsyncTask需要确保AsyncTask正确地取消。
2.不好好工作的cancel()
简而言之的答案,有时候起作用。
如果你调用了AsyncTask的cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用onPostExecute()方法。但是实际上这是让应用程序执行了没有意义的操作。那么是不是我们调用cancel(true)前面的问题就能解决呢?并非如此。如果mayInterruptIfRunning设置为true,会使任务尽早结束,但是如果的doInBackground()有不可打断的方法会失效,比如这个BitmapFactory.decodeStream() IO操作。但是你可以提前关闭IO流并捕获这样操作抛出的异常。但是这样会使得cancel()方法没有任何意义。
3.内存泄露
还有一种常见的情况就是,在Activity中使用非静态匿名内部AsyncTask类,由于Java内部类的特点,AsyncTask内部类会持有外部类的隐式引用。由于AsyncTask的生命周期可能比Activity的长,当Activity进行销毁AsyncTask还在执行时,由于AsyncTask持有Activity的引用,导致Activity对象无法回收,进而产生内存泄露。
4.结果丢失
另一个问题就是在屏幕旋转等造成Activity重新创建时AsyncTask数据丢失的问题。当Activity销毁并重新创建后,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。
5.串行还是并行
AnsycTask执行任务时,内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask.execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。对于内部的线程池不同版本的Android的实现方式是不一样的:
3.0之前规定同一时刻能够运行的线程数为5个,线程池总大小为128。也就是说当我们启动了10个任务时,只有5个任务能够立刻执行,另外的5个任务则需要等待,当有一个任务执行完毕后,第6个任务才会启动,以此类推。而线程池中最大能存放的线程数是128个,当我们尝试去添加第129个任务时,程序就会崩溃。
因此在3.0版本中AsyncTask的改动还是挺大的,在3.0之前的AsyncTask可以同时有5个任务在执行,而3.0之后的AsyncTask同时只能有1个任务在执行,只能串行。为什么升级之后可以同时执行的任务数反而变少了呢?这是因为更新后的AsyncTask已变得更加灵活,如果不想使用默认的线程池,还可以自由地进行配置,同样可以并行。比如使用如下的代码来启动任务:
- Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
- new DownloadTask().executeOnExecutor(exec);
这样就可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor。上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。
下面的两个任务时同时执行呢,还是AsyncTask1执行结束之后,AsyncTask2才能执行呢?实际上是结果依据API不同而不同。
关于AsyncTask时串行还是并行有很多疑问,这很正常,因为它经过多次的修改。如果你并不明白什么时串行还是并行,可以通过接下来的例子了解,假设我们在一个方法体里面有如下两行代码:
- new AsyncTask1.execute();
- new AsyncTask2.execute();
在1.6(Donut)之前:
在第一版的AsyncTask,任务是串行调度。一个任务执行完成另一个才能执行。由于串行执行任务,使用多个AsyncTask可能会带来有些问题。所以这并不是一个很好的处理异步(尤其是需要将结果作用于UI试图)操作的方法。
从1.6到2.3(Gingerbread)
后来Android团队决定让AsyncTask并行来解决1.6之前引起的问题,这个问题是解决了,新的问题又出现了。很多开发者实际上依赖于顺序执行的行为。于是很多并发的问题蜂拥而至。
3.0(Honeycomb)到现在
好吧,开发者可能并不喜欢让AsyncTask并行,于是Android团队又把AsyncTask改成了串行。当然这一次的修改并没有完全禁止AsyncTask并行。你可以通过设置executeOnExecutor(Executor)来实现多个AsyncTask并行。关于API文档的描述如下
If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel
6.真的需要AsyncTask么
并非如此,使用AsyncTask虽然可以以简短的代码实现异步操作,但是正如本文提到的,你需要让AsyncTask正常工作的话,需要注意很多条条框框。推荐的一种进行异步操作的技术就是使用Loaders。这个方法从Android 3.0 (Honeycomb)开始引入,在android支持包中也有包含。可以通过查看官方的文档来详细了解Loaders。
3.Handler 以及ThreadHandler
ThreadHandler其实就是封装了looper messageQueue 和线程的handler,ThreadHandler相比AsyncTask 更加笨重些,但是ThreadHandler更适合处理多线程的操作,单个异步处理推荐用AsyncTask,一个具体的使用场景就是在IntentService中的具体使用
4.Intentservice
intentService 是一种特殊的 Service ,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能使用 IntentService。
IntentService 可用于执行后台耗时的任务,当任务执行后它会自动停止,同时由于 IntentService 是服务的原因,这导致它的优先级比单纯的线程要高很多,比较适合一些高优先级的后台任务。
IntentService 封装了 HandlerThread 和 Handler:
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">public</span> <span class="hljs-keyword" style="box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>() {</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-comment" style="box-sizing: border-box;">// TODO: It would be nice to have an option to hold a partial wakelock</span></code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-comment" style="box-sizing: border-box;">// during processing, and to have a static startService(Context, Intent)</span></code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-comment" style="box-sizing: border-box;">// method that would launch the service & hand off a wakelock.</span></code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">super</span>.onCreate();</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> HandlerThread thread = <span class="hljs-keyword" style="box-sizing: border-box;">new</span> HandlerThread(<span class="hljs-string" style="box-sizing: border-box;">"IntentService["</span> + mName + <span class="hljs-string" style="box-sizing: border-box;">"]"</span>);</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> thread.start();</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> mServiceLooper = thread.getLooper();</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> mServiceHandler = <span class="hljs-keyword" style="box-sizing: border-box;">new</span> ServiceHandler(mServiceLooper);</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> }</code>
<ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul></ul>
当 IntentService 被第一次启动时,它的 onCreate 方法就会被调用,onCreate方法会创建一个 HandlerThread,然后使用它的 Looper 来构造一个 Handler 对象 mServiceHandler,这样通过mServiceHandler 发送的消息最终都会在 HandlerThread 中执行,从这个角度来看,IntentService 也可用于执行后台任务。
每次启动 IntentService,它的 onStartCommand 方法就会调用一次,IntentService 在 onStartCommand 中处理每个后台任务的 Intent。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">public</span> <span class="hljs-keyword" style="box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onStart</span>(Intent intent, <span class="hljs-keyword" style="box-sizing: border-box;">int</span> startId) {</code>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> Message msg = mServiceHandler.obtainMessage();</code>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> msg.arg1 = startId;</code>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> msg.obj = intent;</code>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> mServiceHandler.sendMessage(msg);</code>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> }</code>
<ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul></ul>
IntentService 仅仅通过 mServiceHandler 发送一个消息,这个消息会在 HandlerThread 中处理。 mServiceHandler 收到消息后,会将 Intent 对象传递给 onHandleIntent 方法去处理。
注意:这个 Intent 对象的内容和外界的 startService(intent) 中的内容是完全一致的,通过这个 Intent 对象即可解析出外界启动 IntentService 时所传入的参数,这样 onHandleIntent 方法就可以对不同的后台任务做处理了。当 onHandleIntent 方法执行结束后,IntentService 会通过 stopSelf(int startId) 方法来尝试停止服务。
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">private</span> <span class="hljs-keyword" style="box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box;">ServiceHandler</span> <span class="hljs-keyword" style="box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span> {</span></code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ServiceHandler</span>(Looper looper) {</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">super</span>(looper);</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> }</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-annotation" style="box-sizing: border-box;">@Override</span></code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="box-sizing: border-box;">public</span> <span class="hljs-keyword" style="box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">handleMessage</span>(Message msg) {</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> onHandleIntent((Intent)msg.obj);</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> stopSelf(msg.arg1);</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> }</code>
<code class="hljs java has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: "Source Code Pro", monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> }</code>
<ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><ul><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul></ul>
IntentService 的 onHandleIntent 方法是一个抽象方法,它的作用就是从 Intent 参数中区分具体的任务并执行这些任务。 如果目前只存在一个后台任务,那么 onHandleIntent 方法执行完这个任务后,stopSelf(int starId)就会直接停止任务,如果有多个任务,会执行完最后一个任务再停止服务,这些任务会按照外界发起的顺序排队执行。
5.Android中的线程池
线程池的优点:
- 重用线程池的线程,避免因为线程的创建和销毁所带来的性能开销;
- 能有效的控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象;
- 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能;
Android 中的线程池来源于 Java 中的 Executor,Executor 是一个接口,真正的线程池实现为 ThreadPOOLExecutor。
ThreadPoolExecutor
ThreadPoolExecutor 是线程池的真正实现,它的构造方法提供了一系列参数来配置线程池:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ThreadPoolExecutor</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> corePoolSize,
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maximumPoolSize,
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
-
corePoolSie
线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使它们处于闲置状态。如果将 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个事件间隔由keepAliveTime 所指定,当等待事件超过 keepAliveTime 所指定的时间,核心线程会被终止。
-
maximumPoolSize
线程池中所能容纳的最大线程数,当活动线程数达到这个数值后,后续的任务会被阻塞。
-
keepAliveTime
非核心线程闲置是的超时时长,超过这个时长,非核心线程就会被回收。如果将 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 true,keepAliveTime 同样会作用于核心线程。
-
unit
用于指定 keepAliveTime 参数的时间单位,这是一个枚举,常用的有 TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)以及TimeUnit.MINUTES(分钟)等。
-
workQueue
线程池中的任务队列,通过线程池的 execute 方法提交的 Runnable 对象会存储在这个参数中。
-
threadFactory
线程工厂,为线程池创建新线程的功能。ThreadFactory 是一个接口,它只有一个方法: Thread newThread(Runnable r).
ThreadPoolExecutor 执行任务时大致遵循如下规则:
- 如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
- 如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会直接插入到任务队列中排队等待执行。
- 如果在步骤2中无法将任务插入到任务队列里,这往往是由于任务队列已满,这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
- 如果步骤3中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor 会调用 RejectedExecutionHandler 的 rejectedExecution 方法来通知调用者。
线程池的分类
1. FixedThread
通过Executors 的 newFixedThreadPool 方法来创建,它是一种线程数量固定的线程池,当线程处于空闲状态时,它们不会被回收,除非线程池被关闭了。
当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有空闲线程。由于此线程池只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求。
2. CacheThreadPool
通过Executors 的 newCacheThreadPool 方法来创建,它是一种线程数量不定的线程池,它只有非核心线程,并且最大线程数为 Integer.MAX_VALUE。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就利用空闲的线程来处理新任务。线程池中的空闲线程超时时长为60s,超过就会被回收,线程池的任务会立即执行。所以这类线程池比较适合执行大量的耗时较少的任务。当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CacheThreadPool 之中实际上是没有任何线程的,它几乎是不占用任何系统资源的。
3. ScheduleThreadPool
通过Executors 的 ScheduleThreadPool 方法来创建,它的核心线程数是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收。ScheduleThreadPool 这类线程池主要用来执行定时任务和具有固定周期的重复任务。
4. SingleThreadExecutor
通过Executors 的 SingleThreadExecutor 方法来创建,这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor 的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题