【java】一个简单的线程池

线程池的作用是充分利用CPU资源,减小线程创建、注销的系统开销。线程池一般应该包括四个部分:

    1、线程池管理器

    2、任务队列

    3、任务接口

    4、工作线程

 

线程池是一个典型的生产者-消费者模式的应用,可以充分利用java中的多线程API。

 

任务的分配有两种方式:

1、由管理器分配,这时资源的同步需要由管理器实现;

2、工作线程主动获取任务,这时资源的同步需要由任务队列实现;

本例采用第二种方式。

 

一、一个简单的例子 

 

1、线程池管理器

 

对线程池进行统一管理,应该维护一个工作线程的列表、一个任务队列。

至少对外开放一个运行接口,供用户调用来启动线程池。也可以有一个停止方法stop(),本例中没有写。

 

 

/*
 * 线程池管理器
 */
public class PoolManager {

 private MyQueue q; //任务队列
 private Worker [] ths; //线程数组
 
 public PoolManager(int workerNum, MyQueue q){
  ths = new Worker[workerNum];
  this.q = q;
 }
 

//启动线程池
 public void execute(){ 
  
  for(int i=0; i<ths.length; i++){
   Worker w = new Worker(i, q);
   ths[i] = w;
  }
  
  for(int i=0; i<ths.length; i++){
   ths[i].start();
  }
 }

}

 

 

2、任务队列

 

本例中,任务队列是一个先进先出的数据结构,当然可以按照需求采用其他的数据结构。

任务队列用来保存用户的工作任务,属于生产者-消费者里面的产品角色。至少应该对外开放两个接口:任务入队列、任务出队列,并实现方法同步。

 

/*
 * 任务队列
 */
public class MyQueue {
 private IJob[] jobArray; //采用数组的方式存储,也可以用链表等方式
 private int front; //队列头
 private int tail; //队列尾
 private int size; 
 private boolean fullFlag;

 public MyQueue(int i){
  this.jobArray = new IJob[i];
  front = 0;
  tail = 0;
  size = 0;
 }

//出队列

 public synchronized IJob pop(){ 
  this.notifyAll();
  if(front == tail && !fullFlag){
   try {
    this.wait(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }

  IJob job = jobArray[front];
  jobArray[front] = null;
  front = (front + 1)%jobArray.length;
  size--;
  fullFlag = false;
  return job;
 }

//入队列

 public synchronized boolean put(IJob job) throws Exception{
  this.notifyAll();
  if(null == job){
   throw new Exception("不能入null");
  }
  
  if(fullFlag){
   try {
    this.wait(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }

  jobArray[tail] = job;
  tail = (tail + 1)%jobArray.length;
  size++;
  if(front == tail) fullFlag = true;
  return true;
 }

 public long getSize() {
  return size;
 }

 public boolean isEmpty(){
  return size==0?true:false;
 }

 public boolean isFull(){
  return fullFlag;
 }

 public String toString(){
  StringBuffer sb = new StringBuffer().append("[");
  for(int i=0; i<jobArray.length-1; i++){
   if(null != jobArray[i]){
    sb.append(((JobImpl)jobArray[i]).name + ",");
   }else{
    sb.append("null" + ",");
   }
  }
  if(jobArray[jobArray.length-1] != null){
   sb.append(((JobImpl)jobArray[jobArray.length-1]).name + "]");
  }else{
   sb.append("null" + "]");
  }
  return sb.toString();
 }

}

 

3、任务接口

 

用户任务必须实现这个接口

 

/*
 * 任务接口
 */
public interface IJob {
 public void doJob();
}

 

4、工作线程

 

即消费者。

理论上来说,工作线程可以是一个死循环,不停地检查任务队列中有无需要执行的任务。

 

/*
 * 工作线程
 */
public class Worker extends Thread {
 int _idx;
 MyQueue q = new MyQueue(100);
 
 public Worker(int i, MyQueue q){
  this._idx = i;
  this.q = q;
 }
 
 public void run(){
  while(true){
   
   IJob job = q.pop();
   if(null == job){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    continue;
   }
   job.doJob();
  }
 }
 
 public String toString(){
  return "线程_" + _idx;
 }
}

 

5 测试

 

/*
 * 用户的任务
 */

class JobImpl implements IJob{
 String name;
 JobImpl(int i){
  name = "["+i+"]";
 }
 public void doJob() {
  System.out.println("[" + Thread.currentThread().getName() + "]执行" + name);
  try {
   Thread.sleep(100);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

 

/*
 * 测试的main函数
 */

 public static void main(String [] a) throws Exception{
  IJob job = null;
  MyQueue q = new MyQueue(10);
  PoolManager pm = new PoolManager(2, q);
  pm.execute();
  
  for(int i=0; i<100; i++){
   job = new JobImpl(i);
   System.out.println(((JobImpl)job).name + "入队列");
   q.put(job);
  }
  
  Thread.sleep(10*1000);
  
  for(int i=101; i<150; i++){
   job = new JobImpl(i);
   System.out.println(((JobImpl)job).name + "入队列");
   q.put(job);
  }
  
 }

 

 

二、优化后的线程池 

 

 

这个线程池的例子有几个缺点:

    1、向用户开放的接口太多,暴露了大部分内部结构;

    2、队列、工作线程都采用的面向实现编程,拓展性不够好;

    3、线程池只能启动无法手动停止。

解决方法:

    1、只向用户开放3个接口:任务Interface、线程池的启动和停止、向池中添加任务;

    2、队列、工作线程采用接口编程,后期可以扩展不同的队列及工作线程;

    3、增加线程池的停止方法stop()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值