之前有一节描述了在Android中多线程的应用场景,与Handler结合使用,这一节我们来稍微的详细的来描述一下使用线程池来分配管理线程调度并实现线程队列。
线程池的介绍
线程池的原理:通过减少线程创建和销毁的消耗,使用开始创建的线程来执行我们需要的任务来提高线程执行效率。减少了线程的创建和销毁的消耗。
一条线程大概需要1M的内存,如果在一个高并发的应用里面,又不设置一个最大值来限制线程数量是非常危险的。创建一个具有固定数量线程调度的线程池有助与内存的节省以及线程的调度利用,在任务队列中如果没有超过这个最大值的时候,每次来一条任务都新建一条线程来执行他,即使有空闲的线程也不会调用之前创建好的线程,等到任务数量超过了这个值之后,那么如果有先的任务进来但是有空闲的线程就会调用闲置的线程来执行任务,如果没有的话,就会等待任务执行完,分配空闲的进程来执行这个任务。线程池可以重复利用减少创建销毁的消耗来减少消耗。
以上是对线程池的一个大致的介绍,下面我们通过一个实例来看一下使用线程池分配线程来执行一个线程队列任务。
首先我们创建一个任务类,来模拟任务:
public class Task implements Runnable {
private String name;
private static final int SLEEP_TIME = 1000;
public Task(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void run() {
try {
Thread.sleep(SLEEP_TIME);// 模拟处理任务的过程。
System.out.println("thread " + name + " is running !");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以看到这个类是集成Runnable的,因为线程池执行的任务都是Runnable类型的。我们重写run方法,让线程休眠一秒,来模拟任务执行过程。
接下来我们要实现一个单例模式的任务管理类,来对当前的任务进行管理:添加,删除。要对一个线程队列进行管理,我们当然智能一直对这同一个队列进行管理,而不是一直创建,单例模式就可以很好的实现这个场景:
public class TaskManager {
private LinkedList<Task> tasks ;
private Set<String> taskNames ;
private static TaskManager manager;
/**
* 实现单例模式对线程进行管理
* @return
*/
public static TaskManager getInstance(){
if(manager == null){
manager = new TaskManager() ;
}
return manager ;
}
private TaskManager(){
tasks = new LinkedList<Task>() ;
taskNames = new HashSet<String>() ;
}
public void addTask(Task task){
if(!isTaskExist(task)){
System.out.println("task "+task.getName() + " is added to the queue. ");
tasks.add(task);
}else{
System.out.println("task "+task.getName() + " is already in the queue. ");
}
}
/**
* 队列线程选取执行
* @return
*/
public Task getTask(){
if(tasks.size() > 0){
Task currentTask = tasks.removeFirst() ;
return currentTask ;
}
return null ;
}
public boolean isTaskExist(Task task){
if(taskNames.contains(task.getName())){
return true ;
}else{
taskNames.add(task.getName()) ;
System.out.println( " thread "+task.getName() + " is added to the queue .");
return false ;
}
}
}
使用static变量让其单独占用内存实现单例模式。
接下来就是线程池拿来拿到队列中的任务进行执行了。
public class Pool implements Runnable {
private ExecutorService executorService;
private static final int THREAD_POOL_SIZE = 5;
private static final int SLEEP_TIME = 2000;
private boolean isStop = false ;
public Pool() {
executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
}
public void run() {
while (!isStop) {
Task currentTask = TaskManager.getInstance().getTask();
if (currentTask != null) {
executorService.execute(currentTask);
} else {
System.out.println("there is no task in the queue . ");
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if(isStop){
executorService.shutdown() ;
System.out.println("thread pool is shut down .");
}
}
public void setIsStop(boolean isStop){
this.isStop = isStop ;
}
}
这里我们使用executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);这个来创建一个最大线程数为5的线程池。由于在TaskManager里面的getTask方法已经做好了取任务模式了,这里我们只需要大胆的取到任务再执行就行了。
准备工作都做好了,我们应该看下效果了:
public class RunPool {
public static void main(String[] args) {
new Thread(new Pool()).start();
String[] taskNames = new String[] { "cvil-1", "cvil-2", "cvil-3",
"cvil-4", "cvil-3", "cvil-2", "cvil-5" };
for (String taskName : taskNames) {
TaskManager.getInstance().addTask(new Task(taskName));
}
}
}