线程池就好像...
一个工厂从外面接业务(任务)回来,而它养了一定数量的工人,工人主动去领取任务,然后负责这个任务的实施。
然而这个工厂怎么管理好业务和工人,怎么管理好任务的分配而不发生错误,即需要一个良好的机制了。
回到线程池,一样的道理。
有以下几个基本点:(这里针对简单基础的情况)
1. 用一个队列管理任务,任务包括创建时间、提交时间、执行时间、结束时间等描述任务执行过程的属性。(就好像一个工程项目做的施工计划或者合同计划类似属性)
2.用一个队列管理工作线程(工人),工作线程主动到线程任务队列中拿任务,如果队列为空则等待,直到有任务进来然后唤醒他们——有活干了!
3.有一个后台线程(监理)负责监控这些工作线程的工作状态,是空闲还是忙碌。
4.任务接口(或则抽象类),所有执行的任务必须符合标准。(就好像一个公司大部分只做相关业务的单子,除了......)
下面给出代码了,也是参考了网上的,进行了适当的调整,并且给出了适当的注释!
1.task接口。
//任务创建时间
private Date createT = null;
//提交执行时间
private Date submitT = null;
//开始执行时间
private Date runingT = null;
//结束执行时间
private Date finishT = null;
//任务编号
private int taskID ;
//构造
public Task(){
this.createT = new Date();
}
@Override
public void run() {
core();
}
//核心业务代码,即任务的主要工作。
public abstract void core();
//任务详细信息
public void display(){
System.out.println("/t任务标示:" + this.taskID + ";/t创建时间:" + this.createT + ";/t提交时间:" + this.submitT + ";/t开始执行时间:" +
this.runingT + ";/t结束执行的时间:" + this.finishT );
}
public Date getCreateT() {
return createT;
}
public void setCreateT(Date createT) {
this.createT = createT;
}
public Date getSubmitT() {
return submitT;
}
public void setSubmitT(Date submitT) {
this.submitT = submitT;
}
public Date getRuningT() {
return runingT;
}
public void setRuningT(Date runingT) {
this.runingT = runingT;
}
public Date getFinishT() {
return finishT;
}
public void setFinishT(Date finishT) {
this.finishT = finishT;
}
public int getTaskID() {
return taskID;
}
public void setTaskID(int taskID) {
this.taskID = taskID;
}
}
2.worker——工作线程
//构造
public Worker(int id){
this.id = id;
start();
}
//停止当前线程
public void Stop(){
this.isRunning = false;
}
//获得isRunning的状态
public boolean getIsRunning(){
return this.isRunning;
}
//获得isWating的状态
public boolean getIsWaiting(){
return this.isWaiting;
}
@Override
public void run() {
//循环执行任务队列中的任务,前提是当前线程是可运行的,即isRunning=true
while(isRunning){
//声明一个任务
Task task = null;
//从任务队列中取出一个任务
synchronized (ThreadPool.getTasks()) {
//如果任务队列为空,则让任务队列等待一段时间再看看是否有任务可执行。
while(ThreadPool.isTaskEmp()){
try {
ThreadPool.getTasks().wait(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//当上面的循环执行结束,则说明任务队列不为空
//取出第一个任务进行执行
task = ThreadPool.getTasks().remove(0);
}
if( task != null ){
//当任务为可执行任务时(not null),则这个线程有任务要处理了,则他的状态就不是闲置了。
this.isWaiting = false;
//执行任务
task.run();
}
//任务执行结束
//重新置回当前线程的状态为闲置
this.isWaiting = true;
ThreadPool.getTasks().remove(task);
task = null ;
}// end synchronized
}
}
3.ThreadPool——线程池
//
public static List<Task> getTasks() {
return tasks;
}
//单例
public static synchronized ThreadPool getInstance(){
if(pool == null){
return new ThreadPool();
}else{
return pool;
}
}
//构造
private ThreadPool(){
this.workers = new Worker[MAX_THREAD_COUNT];
for (int i = 0; i < this.workers.length; i++) {
this.workers[i] = new Worker(i);
}
}
//构造(重载)
// private ThreadPool(int maxThreadCount){
// this.MAX_THREAD_COUNT = maxThreadCount;
// this.workers = new Worker[maxThreadCount];
// for (int i = 0; i < maxThreadCount; i++) {
// this.workers[i] = new Worker(i);
// }
// }
//销毁线程池
public synchronized void destory(){
for (int i = 0; i < this.workers.length; i++) {
//这里不是线程的stop方法。
this.workers[i].Stop();
//清除线程
this.workers[i] = null;
}
//清除任务队列。
this.tasks.clear();
}
//获得任务队列是否为空
public static boolean isTaskEmp(){
return tasks.isEmpty();
}
//获得当前线程池的情况
public void display(){
System.out.println("线程池情况:");
for (int i = 0; i < this.workers.length; i++) {
System.out.println("/t"+this.workers[i].getId() + "/t" + (this.workers[i].getIsWaiting()==true?"闲置":"工作"));
}
}
//添加单个任务
public void addTask(Task newTask){
synchronized (this.tasks) {
//设定任务标示
newTask.setTaskID(++this.taskid);
//设定任务提交时间
newTask.setSubmitT(new Date());
//将任务加入到任务队列当中
this.tasks.add(newTask);
// System.out.print("添加任务:" );
// newTask.display();
//唤醒任务队列,因为在线程取任务的时候若任务队列为空则会将tasks.wait();
//这里需要唤醒。
this.tasks.notifyAll();
}
}
}
4.monitor——监控类
public Monitor(ThreadPool p){
this.pool = p ;
}
@Override
public void run() {
while(true){
pool.display();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
5.以下是配合测试的,具体的任务TaskTest
/**
* @author huangfox
* 简单实现一个任务类。
*/
public class TaskTest extends Task {
@Override
public void core() {
System.out.println("任务【" + super.getTaskID() + "】开始...");
try {
//模拟具体业务运行时间
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务【" + super.getTaskID() + "】结束...");
}
}
6.测试主程序
虽然是入门级的线程池,但是基本的原理还是比较清晰地。