为什么要使用线程池
- 当同时并发多个网络线程时,引入线程池技术会极大地提高APP的性能。
- 显著减少了创建线程的数目。
- 防止内存过度消耗。控制活动线程的数量,防止并发线程过多。
四种线程池各自的特点
- newCachedThreadPool()
缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中。能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。缓存型池子通常用于执行一些生存期很短的异步型任务 。 - newFixedThreadPool()
fixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程 其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子。和cacheThreadPool不同:fixedThreadPool池线程数固定,但是0秒IDLE(无IDLE)。这也就意味着创建的线程会一直存在。所以fixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器。 - newScheduledThreadPool()
调度型线程池。这个池子里的线程可以按schedule依次delay执行,或周期执行 。0秒IDLE(无IDLE)。 - SingleThreadExecutor
单例线程,任意时间池中只能有一个线程 。用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)。
Activity内容
package com.test.wjy.statusbartest.thread; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import com.test.wjy.statusbartest.R; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; /** * Created by wjy on 2017/5/8. * 线程池 */ public class ThreadPoolActivity extends Activity implements View.OnClickListener { /** 总共多少任务,(根据CPU个数决定创建活动线程的个数,这样取的好处就是让手机承受的住) */ // private static final int count = Runtime.getRuntime().availableProcessors() * 3 + 2; /** 总任务数 */ private static final int count = 3; /** 所有任务都一次性开始的线程池 */ private static ExecutorService mCacheThreadExecutor = null; /** 每次执行限定任务个数的线程池 */ private static ExecutorService mFixedThreadExecutor = null; /** 创建一个可以在指定时间里执行任务的线程池,亦可重复执行 */ private static ScheduledExecutorService mScheduledThreadExecutor = null; /** 每次只执行一个任务的线程池 */ private static ExecutorService mSingleExecutor = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_threadpool); initView(); initExcutorService(); } private void initView(){ findViewById(R.id.btn_mCacheThreadExecutor).setOnClickListener(this); findViewById(R.id.btn_mFixedThreadExecutor).setOnClickListener(this); findViewById(R.id.btn_mScheduledThreadExecutor).setOnClickListener(this); findViewById(R.id.btn_mSingleExecutor).setOnClickListener(this); } private void initExcutorService(){ mCacheThreadExecutor = Executors.newCachedThreadPool();//一个没有限制最大线程数的线程池 mFixedThreadExecutor = Executors.newFixedThreadPool(count);//限制线程池大小为count的线程池 mScheduledThreadExecutor = Executors.newScheduledThreadPool(count);//一个可按指定时间可周期性执行的线程池 mSingleExecutor = Executors.newSingleThreadExecutor();//每次只执行一个任务的线程池 } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_mCacheThreadExecutor: ExecutorServiceThread(mCacheThreadExecutor); break; case R.id.btn_mFixedThreadExecutor: ExecutorServiceThread(mFixedThreadExecutor); break; case R.id.btn_mScheduledThreadExecutor: ExecutorScheduledThread(mScheduledThreadExecutor); break; case R.id.btn_mSingleExecutor: ExecutorServiceThread(mSingleExecutor); break; } } private void ExecutorServiceThread(ExecutorService executorService){ for (int i = 0; i<9; ++i){ final int index = i; executorService.execute(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("Executor", "Thread:" + Thread.currentThread().getId() + " activeCount:" + Thread.activeCount() + " index:" + index); } }); } } private void ExecutorScheduledThread(ScheduledExecutorService scheduledExecutorService){ for (int i = 0; i < 9; ++i){ final int index = i; scheduledExecutorService.execute(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("Executor", "Thread:" + Thread.currentThread().getId() + " activeCount:" + Thread.activeCount() + " index:" + index); } }); } } }
XML布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp" android:orientation="vertical"> <Button android:id="@+id/btn_mCacheThreadExecutor" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="所有任务都一次性开始的线程池"/> <Button android:id="@+id/btn_mFixedThreadExecutor" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="每次执行限定任务个数的线程池"/> <Button android:id="@+id/btn_mScheduledThreadExecutor" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="可以在指定时间里执行任务的线程池,可重复"/> <Button android:id="@+id/btn_mSingleExecutor" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="每次只执行一个任务的线程池"/> </LinearLayout>
运行结果
1、 所有任务都一次性开始的线程池,一次性执行完
60s之内点击两次btn_mCacheThreadExecutor,60s后再次点击,一共三次点击
可以发现:第一次点击开启了9个线程。没有复用任何线程,60s内第二次点击,全部复用了第一次点击开启的线程。60s后第三次点击,由于IDLE机制,原来开启的线程被自动终止,重新开启了9个新线程。
2、每次执行限定任务个数的线程池,本例中限定的一次执行3个,则每两秒执行3个
点击btn_mFixedThreadExecutor,60s后再次点击,无论多长时间再次点击btn_mFixedThreadExecutor,都在复用已经创建了的3个线程。0秒IDLE(无IDLE)。
3、可以在指定时间里执行任务的线程池,可重复(设定的每隔两秒执行3个)
点击btn_mScheduledThreadExecutor,60s后再次点击,这个和btn_mFixedThreadExecutor一样,区别是首次创建Thread有个启动延迟时间,本例子是2s。0秒IDLE(无IDLE)
4、每次只执行一个任务的线程池(一次执行一个,直到所有的都执行完)