您的位置:首页 > 其它

线程学习笔记(十二)-线程池

2017-08-14 17:20 417 查看
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。本实例介绍如何运用线程池实现任务的执行。
技术要点
运用线程池实现任务的执行的技术要点如下:
如果某个线程在托管代码中空闲,则线程池将插入另一个辅助线程(线程池)来使所有处理器保持繁忙;如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则 线程池将在一段时间后创建另一个辅助线程(线程池),但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但它们要等到其他线程完成后后才启动。
任务放在LinkedList中,由于LinkedList不支持同步,所以在添加任务和获取任务的方法声明中必须使用synchronized关键字
关闭线程池时,通过ThreadGroup线程组获得池中所有活动线程的引用,依次调用Thread类的join()方法等待活动线程执行完毕。当所有线程运行结束是,线程池才算被关闭。
package core;

import java.util.LinkedList;

class ThreadPool extends ThreadGroup {
private static int threadPool_ID = 1; // 线程池的编号
private LinkedList<Runnable> taskQueue; // 工作任务队列
private boolean isClosed = false;// 线程池是否关闭

private class TaskThread extends Thread {
private int id;

public TaskThread(int id) {
super(ThreadPool.this, id + "");// 将线程加入到当前线程组中
this.id = id;
}

public void run() {
while (!isInterrupted()) {// 判断线程是否被中断
Runnable task = null;
task = getTask(id);// 取出任务
// 如果getTask()返回null或者线程执行getTask()被中断,则结束此线程
if (task == null)
return;
try {
task.run(); // 运行任务
} catch (Throwable t) {
t.printStackTrace();
}

}
}
}

public synchronized Runnable getTask(int id) {
try {
while (taskQueue.size() == 0) {// 循环使线程等待任务
if (isClosed)
return null;
System.out.println("工作线程" + id + "等待任务");
wait();// 如果任务队列中没有任务,就等待任务
}
} catch (InterruptedException e) {
System.out.println("等待任务出现错误: " + e.getMessage());
}
System.out.println("工作线程" + id + "开始执行任务。。。。");
return (Runnable) taskQueue.removeFirst();// 返回第一个任务并从队列中删除
}

public ThreadPool(int poolsize) {
super(threadPool_ID + " ");
setDaemon(true);
taskQueue = new LinkedList<Runnable>();// 创建工作任务队列
for (int i = 0; i < poolsize; i++) {// 循环创建任务线程
new TaskThread(i).start();//根据线程池数据创建任务线程并启动线程
}
}
public   synchronized void exexcuteTask(Runnable task){//添加新任务并执行任务
if(isClosed){
throw new IllegalStateException();//抛出不合理状态异常
}
if(task !=null){
taskQueue.add(task);//向任务队列中加入一个任务
notify();//唤醒线程池中等待任务的工作任务线程
}
}
public void waitTaskFinish(){
synchronized(this){
isClosed=true;
notifyAll();//唤醒所有等待任务的工作任务线程
}
Thread[] threads=new Thread[activeCount()];//创建线程组中活动的线程组
int count=enumerate(threads);//获得线程组中当前所有活动的工作线程
for (int i = 0; i < count; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
System.out.println("任务执行出错: " + e.getMessage());

}
}
}
public synchronized void closeThreadPool(){//关闭线程池
if(!isClosed){    //判断标识
waitTaskFinish();  //等待任务线程执行完毕
isClosed=true;   //标识为真
taskQueue.clear();//任务队列清空
interrupt();//唤醒线程池中所有的工作线程
}
}
}

public class TextThreadPool {
private static Runnable createTask(final int taskID) {// 创建任务方法
return new Runnable() {
@Override
public void run() {
System.out.println("任务开始,编号为" + taskID);
System.out.println("start task");
System.out.println("任务结束,编号为" + taskID);
}
};
}

public static void main(String[] args) {
ThreadPool threadPool=new ThreadPool(3); //初始化创建3个任务线程的线程池,等待执行任务
try {//休眠600毫秒,让线程池中的任务线程全部运行
Thread.sleep(600);
} catch (InterruptedException e) {
System.out.println("线程休眠出错: "+e.getMessage());
}
for (int i = 0; i < 5; i++) { //循环创建并执行任务
threadPool.exexcuteTask(createTask(i));
}
threadPool.waitTaskFinish();//等待所有任务执行完毕
threadPool.closeThreadPool();//关闭线程池
}
}




源程序解读
(1)TextThreadPool类的createTask()方法根据任务编号执行指定的任务。在类的main()主方法中实例化三个ThreadPool对象作为线程池,Thread类的sleep()方法使线程休眠0.6秒,运用循环执行创建的工作任务,如果没有创建工作任务,则线程池的三个ThreadPool则会一直等待,调用waitTaskFinish()方法等待所有的任务执行完毕再关闭线程池。
(2)内部类ThreadPool继承线程组类ThreadGroup实现线程池的功能。其私有内部类TaskThread继承Thread线程类,扩展run()方法。在run()方法中根据标识为真进行循环。根据Thread类的getTask()方法获得Runnable任务对象,调用任务对象的run()方法执行任务。
(3)ThreadPool类的构造方法传入线程池中工作线程的数量,设置该类为守护线程类,并创建双向链表。运用循环创建任务线程并启动线程。executeTask()方法是往双向链表中添加任务对象并唤醒等待任务的工作任务线程。getTask()方法根据编号获得指定的任务,并移除双向链表中的双向链表中的第一个任务线程。
(4)waitTaskFinish()方法是等待任务线程执行所有的任务。在其同步块中唤醒等待任务的工作任务线程并设置标识为真。根据活动的线程数创建现场数组,根据活动的线程获得线程组中当前所有活动的工作线程,再运用循环通过join()方法等待所有工作线程结束。closeThreadPool()方法判断标识,如果标识为真,则调用waitTaskFinish()方法将等待的任务线程的所有的任务执行完毕。若设置标识为假,清空双向链表中的任务,唤醒线程池中的所有工作线程。
(5) 对于线程池的三个ThreadPool对象运用了wait和notify的方法。在getTask方法中使用wait方法来等待工作任务,等待list元素;exexcuteTask()方法中把工作任务放入list后,便调用notify方法通知线程池的三个ThreadPool对象取工作任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: