线程池的种类
在前面的《 Android开发笔记(四十八)Thread类实现多线程》,我们介绍了线程类Thread的使用,可是缺乏线程的统一管理,这会产生如下问题:
1、无法控制线程的并发数,一旦同时启动多个线程,可能导致程序挂死;
2、线程之间无法复用,每个线程都经历创建、启动、停止的生命周期,资源开销不小;
3、线程不能被外部有效地杀死,虽然Thread类提供了stop方法,但该方法已经过时,并不推荐使用;
基于以上问题,Java提供了线程池机制,用于对程序内部的线程作统一管理,统一分配、统一调度。Java把线程池分为两大类:普通线程池、定时器线程池,最新的java1.8新加了一类分支/聚合线程池(即ForkJoinPool),但Android尚无ForkJoinPool的定义,所以本文的讨论仅限于前两类。
再具体一点,Android中用到的线程池一共五种,它们都在Executors类中创建,分别是:
1、newCachedThreadPool : 创建一个无个数限制的线程池。
2、newFixedThreadPool : 创建线程数量固定的线程池。
3、newSingleThreadExecutor : 创建只有单个线程的线程池。
4、newScheduledThreadPool : 创建线程数量固定的定时器线程池。
5、newSingleThreadScheduledExecutor : 创建只有单个线程的定时器线程池。
上述五个方法返回的线程池对象都是ExecutorService,它是线程池服务的接口。ExecutorService接口有两个派生类,分别是普通线程池ThreadPoolExecutor,以及定时器线程池ScheduledExecutorService。
ThreadPoolExecutor
要生成普通线程池对象,有两种办法:
1、调用Executors类的方法newCachedThreadPool、newFixedThreadPool,这两个方法返回的类型都是ThreadPoolExecutor。
注意不能用newSingleThreadExecutor,该方法返回的类型是FinalizableDelegatedExecutorService,而不是ThreadPoolExecutor。
2、使用ThreadPoolExecutor自身的构造函数来构建线程池对象,其中构造函数的参数说明如下:
int corePoolSize : 最小线程个数
int maximumPoolSize : 最大线程个数
long keepAliveTime : 线程活动时长
TimeUnit unit : 时间单位。一般取值为TimeUnit.SECONDS表示秒;TimeUnit.MILLISECONDS表示毫秒;TimeUnit.MICROSECONDS表示微妙。
BlockingQueue<Runnable> workQueue : 设置等待队列。取值new LinkedBlockingQueue<Runnable>()即可,默认表示等待队列无穷大,此时工作线程等于最小线程个数;当然也可在参数中指定等待队列的大小,此时工作线程数等于总任务数减去等待队列大小,且工作线程数位于最小线程个数与最大线程个数之间。
若计算得到的工作线程数小于最小线程个数,则工作线程数等于最小线程个数;若工作线程数大于最大线程个数,则系统会扔出异常java.util.concurrent.RejectedExecutionException,并不会自动让工作线程数等于最大线程个数。所以等待队列大小要么取默认值(即不设置),要么设的尽可能大,不然一旦程序启动大量线程,便会异常报错。
ThreadFactory threadFactory : 一般默认即可。
下面是ThreadPoolExecutor的常用方法说明:
execute : 向执行队列添加指定的Runnable任务。
remove : 从执行队列移除指定的Runnable任务。
shutdown : 关闭线程池。
isTerminated : 判断线程池是否关闭。
setCorePoolSize : 设置最小线程个数。
setMaximumPoolSize : 设置最大线程个数。
setKeepAliveTime : 设置线程活动时长。
getPoolSize : 获取当前的线程个数。
getActiveCount : 获取当前的活动线程个数。
ScheduledExecutorService
前面的博文《 Android开发笔记(五十)定时器AlarmManager》,提到了两类定时器,分别是Java自带的Timer/TimerTask,以及Android新增的AlarmManager,这里的ScheduledExecutorService则是第三种定时器。
要生成定时器线程池,也有两种办法:
1、调用Executors类的方法newScheduledThreadPool、newSingleThreadScheduledExecutor,这两个方法返回的类型都是ScheduledExecutorService;
2、使用ScheduledThreadPoolExecutor的构造函数来构建线程池对象(该类继承自ThreadPoolExecutor,但实现了ScheduledExecutorService接口),其中构造函数的参数说明如下:
int corePoolSize : 最小线程个数
ThreadFactory threadFactory : 一般默认即可。
RejectedExecutionHandler handler : 一般默认即可。
ScheduledExecutorService继承了ThreadPoolExecutor的所有方法,下面是它多出的几个定时器方法:
schedule : 延迟一段时间后启动任务。
scheduleAtFixedRate : 先延迟一段时间,然后间隔若干时间周期启动任务。
scheduleWithFixedDelay : 先延迟一段时间,然后固定延迟若干时间启动任务。
注意,scheduleAtFixedRate和scheduleWithFixedDelay都是循环执行任务,它们的区别在于,前者的间隔时间从上个任务开始起计算,后者的间隔时间从上个任务结束起计算。
代码示例
下面是ThreadPoolExecutor的使用代码例子:
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.example.exmthreadpool.util.Utils;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class ThreadPoolActivity extends Activity implements OnClickListener {
private final static String TAG = "ThreadPoolActivity";
private TextView tv_desc;
private String mDesc = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_pool);
tv_desc = (TextView) findViewById(R.id.tv_desc);
Button btn_unlimit_pool = (Button) findViewById(R.id.btn_unlimit_pool);
Button btn_multi_pool = (Button) findViewById(R.id.btn_multi_pool);
Button btn_single_pool = (Button) findViewById(R.id.btn_single_pool);
Button btn_custom_pool = (Button) findViewById(R.id.btn_custom_pool);
btn_unlimit_pool.setOnClickListener(this);
btn_multi_pool.setOnClickListener(this);
btn_single_pool.setOnClickListener(this);
btn_custom_pool.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_unlimit_pool) {
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
startPool(pool);
} else if (v.getId() == R.id.btn_multi_pool) {
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
startPool(pool);
} else if (v.getId() == R.id.btn_single_pool) {
ExecutorService pool = Executors.newSingleThreadExecutor();
startPool(pool);
} else if (v.getId() == R.id.btn_custom_pool) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(19));
startPool(pool);
}
}
private void startPool(ExecutorService pool) {
mDesc = "";
for (int i=0; i<20; i++) {
MyRunnable refresh = new MyRunnable(i);
pool.execute(refresh);
}
}
private Handler mMyHandler = new MyHandler(this);
private static class MyHandler extends Handler {
public static WeakReference<ThreadPoolActivity> mActivity;
public MyHandler(ThreadPoolActivity activity) {
mActivity = new WeakReference<ThreadPoolActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
ThreadPoolActivity act = mActivity.get();
if (act != null) {
act.mDesc = String.format("%s\n%s 当前序号是%d",
act.mDesc, Utils.getNowDateTime(), msg.arg1);
act.tv_desc.setText(act.mDesc);
}
}
}
private static class MyRunnable implements Runnable {
private int mIndex;
public MyRunnable(int index) {
mIndex = index;
}
@Override
public void run() {
try {
Thread.sleep(2000);
ThreadPoolActivity act = MyHandler.mActivity.get();
if (act != null) {
Message msg = act.mMyHandler.obtainMessage();
msg.arg1 = mIndex;
act.mMyHandler.sendMessage(msg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
下面是ScheduledExecutorService的使用代码例子:
import java.lang.ref.WeakReference;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.example.exmthreadpool.util.Utils;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class SchedulePoolActivity extends Activity implements OnClickListener {
private final static String TAG = "SchedulePoolActivity";
private TextView tv_desc;
private String mDesc = "";
private int ONCE = 1;
private int RATE = 2;
private int DELAY = 3;
private ScheduledExecutorService mMultiPool;
private ScheduledExecutorService mSinglePool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_schedule_pool);
tv_desc = (TextView) findViewById(R.id.tv_desc);
Button btn_multi_schedule_once = (Button) findViewById(R.id.btn_multi_schedule_once);
Button btn_multi_schedule_rate = (Button) findViewById(R.id.btn_multi_schedule_rate);
Button btn_multi_schedule_delay = (Button) findViewById(R.id.btn_multi_schedule_delay);
Button btn_single_schedule_once = (Button) findViewById(R.id.btn_single_schedule_once);
Button btn_single_schedule_rate = (Button) findViewById(R.id.btn_single_schedule_rate);
Button btn_single_schedule_delay = (Button) findViewById(R.id.btn_single_schedule_delay);
btn_multi_schedule_once.setOnClickListener(this);
btn_multi_schedule_rate.setOnClickListener(this);
btn_multi_schedule_delay.setOnClickListener(this);
btn_single_schedule_once.setOnClickListener(this);
btn_single_schedule_rate.setOnClickListener(this);
btn_single_schedule_delay.setOnClickListener(this);
}
@Override
protected void onStart() {
mMultiPool = (ScheduledExecutorService) Executors.newScheduledThreadPool(3);
mSinglePool = (ScheduledExecutorService) Executors.newSingleThreadScheduledExecutor();
super.onStart();
}
@Override
protected void onStop() {
if (mMultiPool.isTerminated() != true) {
mMultiPool.shutdown();
}
if (mSinglePool.isTerminated() != true) {
mSinglePool.shutdown();
}
super.onStop();
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_multi_schedule_once) {
startPool(mMultiPool, ONCE);
} else if (v.getId() == R.id.btn_multi_schedule_rate) {
startPool(mMultiPool, RATE);
} else if (v.getId() == R.id.btn_multi_schedule_delay) {
startPool(mMultiPool, DELAY);
} else if (v.getId() == R.id.btn_single_schedule_once) {
startPool(mSinglePool, ONCE);
} else if (v.getId() == R.id.btn_single_schedule_rate) {
startPool(mSinglePool, RATE);
} else if (v.getId() == R.id.btn_single_schedule_delay) {
startPool(mSinglePool, DELAY);
}
}
private void startPool(ScheduledExecutorService pool, int type) {
mDesc = "";
for (int i=0; i<1; i++) {
MyRunnable refresh = new MyRunnable(i);
if (type == ONCE) {
pool.schedule(refresh, 1, TimeUnit.SECONDS);
} else if (type == RATE) {
pool.scheduleAtFixedRate(refresh, 0, 3, TimeUnit.SECONDS);
} else if (type == DELAY) {
pool.scheduleWithFixedDelay(refresh, 0, 3, TimeUnit.SECONDS);
}
}
}
private Handler mMyHandler = new MyHandler(this);
private static class MyHandler extends Handler {
public static WeakReference<SchedulePoolActivity> mActivity;
public MyHandler(SchedulePoolActivity activity) {
mActivity = new WeakReference<SchedulePoolActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SchedulePoolActivity act = mActivity.get();
if (act != null) {
act.mDesc = String.format("%s\n%s 当前序号是%d",
act.mDesc, Utils.getNowDateTime(), msg.arg1);
act.tv_desc.setText(act.mDesc);
}
}
}
private static class MyRunnable implements Runnable {
private int mIndex;
public MyRunnable(int index) {
mIndex = index;
}
@Override
public void run() {
try {
Thread.sleep(2000);
SchedulePoolActivity act = MyHandler.mActivity.get();
if (act != null) {
Message msg = act.mMyHandler.obtainMessage();
msg.arg1 = mIndex;
act.mMyHandler.sendMessage(msg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
点此查看Android开发笔记的完整目录