Java自定义线程池和线程总数控制

来源:互联网 发布:数据库系统概念电子书 编辑:程序博客网 时间:2024/05/16 14:01
1 概述

池化是常见的思想,线程池是非常典型的池化的实现,《Java并发编程实战》也大篇幅去讲解了Java中的线程池。本文实现一个简单的线程池。


2 核心类

【1】接口定义

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public interface IThreadPool<Job extends Runnable> {  
  2.     /** 
  3.      * 关闭线程池 
  4.      */  
  5.     public void shutAlldown();  
  6.   
  7.     /** 
  8.      * 执行任务 
  9.      *  
  10.      * @param job 任务 
  11.      */  
  12.     public void execute(Job job);  
  13.   
  14.     /** 
  15.      * 添加工作者 
  16.      *  
  17.      * @param addNum 添加数 
  18.      */  
  19.     public void addWorkers(int addNum);  
  20.   
  21.     /** 
  22.      * 减少工作者 
  23.      *  
  24.      * @param reduceNum 减少数目 
  25.      */  
  26.     public void reduceWorkers(int reduceNum);  
  27. }  
【2】实现类

线程池的核心是维护了1个任务列表和1个工作者列表

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. import java.util.ArrayList;  
  2. import java.util.Collections;  
  3. import java.util.LinkedList;  
  4. import java.util.List;  
  5.   
  6. public class XYThreadPool<Job extends Runnable> implements IThreadPool<Job> {  
  7.   
  8.     // 默认线程数  
  9.     private static int DEAFAULT_SIZE = 5;  
  10.     // 最大线程数  
  11.     private static int MAX_SIZE = 10;  
  12.   
  13.     // 任务列表  
  14.     private LinkedList<Job> tasks = new LinkedList<Job>();  
  15.     // 工作线程列表  
  16.     private List<Worker> workers = Collections  
  17.             .synchronizedList(new ArrayList<Worker>());  
  18.   
  19.     /** 
  20.      * 默认构造函数 
  21.      */  
  22.     public XYThreadPool() {  
  23.         initWokers(DEAFAULT_SIZE);  
  24.     }  
  25.   
  26.     /** 
  27.      * 执行线程数 
  28.      *  
  29.      * @param threadNums 线程数 
  30.      */  
  31.     public XYThreadPool(int workerNum) {  
  32.         workerNum = workerNum <= 0 ? DEAFAULT_SIZE  
  33.                 : workerNum > MAX_SIZE ? MAX_SIZE : workerNum;  
  34.         initWokers(workerNum);  
  35.     }  
  36.   
  37.     /** 
  38.      * 初始化线程池 
  39.      *  
  40.      * @param threadNums 线程数 
  41.      */  
  42.     public void initWokers(int threadNums) {  
  43.         for (int i = 0; i < threadNums; i++) {  
  44.             Worker worker = new Worker();  
  45.             worker.start();  
  46.             workers.add(worker);  
  47.         }  
  48.         // 添加关闭钩子  
  49.         Runtime.getRuntime().addShutdownHook(new Thread() {  
  50.             public void run() {  
  51.                 shutAlldown();  
  52.             }  
  53.         });  
  54.     }  
  55.   
  56.     @Override  
  57.     public void shutAlldown() {  
  58.         for (Worker worker : workers) {  
  59.             worker.shutdown();  
  60.         }  
  61.     }  
  62.   
  63.     @Override  
  64.     public void execute(Job job) {  
  65.         synchronized (tasks) {  
  66.             // 提交任务就是将任务对象加入任务队列,等待工作线程去处理  
  67.             tasks.addLast(job);  
  68.             tasks.notifyAll();  
  69.         }  
  70.     }  
  71.   
  72.     @Override  
  73.     public void addWorkers(int addNum) {  
  74.         // 新线程数必须大于零,并且线程总数不能大于最大线程数  
  75.         if ((workers.size() + addNum) <= MAX_SIZE && addNum > 0) {  
  76.             initWokers(addNum);  
  77.         } else {  
  78.             System.out.println("addNum too large");  
  79.         }  
  80.     }  
  81.   
  82.     @Override  
  83.     public void reduceWorkers(int reduceNum) {  
  84.         if ((workers.size() - reduceNum <= 0))  
  85.             System.out.println("thread num too small");  
  86.         else {  
  87.             // 暂停指定数量的工作者  
  88.             int count = 0;  
  89.             while (count != reduceNum) {  
  90.                 for (Worker w : workers) {  
  91.                     w.shutdown();  
  92.                     count++;  
  93.                 }  
  94.             }  
  95.         }  
  96.     }  
  97.   
  98.     /** 
  99.      * 工作线程 
  100.      */  
  101.     class Worker extends Thread {  
  102.   
  103.         private volatile boolean flag = true;  
  104.   
  105.         @Override  
  106.         public void run() {  
  107.             while (flag) {  
  108.                 Job job = null;  
  109.                 // 加锁(若只有一个woker可不必加锁,那就是所谓的单线程的线程池,线程安全)  
  110.                 synchronized (tasks) {  
  111.                     // 任务队列为空  
  112.                     while (tasks.isEmpty()) {  
  113.                         try {  
  114.                             // 阻塞,放弃对象锁,等待被notify唤醒  
  115.                             tasks.wait();  
  116.                             System.out.println("block when tasks is empty");  
  117.                         } catch (InterruptedException e) {  
  118.                             e.printStackTrace();  
  119.                         }  
  120.                     }  
  121.                     // 不为空取出任务  
  122.                     job = tasks.removeFirst();  
  123.                     System.out.println("get job:" + job + ",do biz");  
  124.                     job.run();  
  125.                 }  
  126.             }  
  127.         }  
  128.   
  129.         public void shutdown() {  
  130.             flag = false;  
  131.         }  
  132.     }  
  133. }  

1 当调用wait()方法时线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备


2 Object的方法:void notify(): 唤醒一个正在等待该对象的线程。void notifyAll(): 唤醒所有正在等待该对象的线程。notifyAll使所有原来在该对象上等待被notify的线程统统退出wait状态,变成等待该对象上的锁,一旦该对象被解锁,它们会去竞争。notify只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其它同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁


3 无需控制线程总数
每调用一次就会创建一个拥有10个线程工作者的线程池。
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class TestService1 {  
  2.     public static void main(String[] args) {  
  3.         // 启动10个线程  
  4.         XYThreadPool<Runnable> pool = new XYThreadPool<Runnable>(10);  
  5.         pool.execute(new Runnable() {  
  6.             @Override  
  7.             public void run() {  
  8.                 System.out.println("====1 test====");  
  9.             }  
  10.         });   
  11.     }  
  12. }  
  13.   
  14. public class TestService2 {  
  15.     public static void main(String[] args) {  
  16.         // 启动10个线程  
  17.         XYThreadPool<Runnable> pool = new XYThreadPool<Runnable>(10);  
  18.         pool.execute(new Runnable() {  
  19.             @Override  
  20.             public void run() {  
  21.                 System.out.println("====2 test====");  
  22.             }  
  23.         });  
  24.     }  
  25. }  


4 控制线程总数
希望在项目中所有的线程调用,都共用1个固定工作者数大小的线程池

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. import javax.annotation.PostConstruct;  
  2. import org.springframework.stereotype.Component;  
  3. import com.xy.pool.XYThreadPool;  
  4.   
  5. /** 
  6.  * 统一线程池管理类  
  7.  */  
  8. @Component  
  9. public class XYThreadManager {  
  10.   
  11.     private XYThreadPool<Runnable> executorPool;  
  12.   
  13.     @PostConstruct  
  14.     public void init() {  
  15.         executorPool = new XYThreadPool<Runnable>(10);  
  16.     }  
  17.   
  18.     public XYThreadPool<Runnable> getExecutorPool() {  
  19.         return executorPool;  
  20.     }  
  21. }  
  22.   
  23. import org.springframework.beans.factory.annotation.Autowired;  
  24. import org.springframework.stereotype.Service;  
  25.   
  26. @Service("testService3")  
  27. public class TestService3 {  
  28.       
  29.     @Autowired  
  30.     private XYThreadManager threadManager;  
  31.       
  32.     public void test() {  
  33.         threadManager.getExecutorPool().execute(new Runnable() {  
  34.             @Override  
  35.             public void run() {  
  36.                 System.out.println("====3 test====");  
  37.             }  
  38.         });  
  39.     }  
  40. }  
  41.   
  42. import org.springframework.beans.factory.annotation.Autowired;  
  43. import org.springframework.stereotype.Service;  
  44.   
  45. @Service("testService4")  
  46. public class TestService4 {  
  47.       
  48.     @Autowired  
  49.     private XYThreadManager threadManager;  
  50.       
  51.     public void test() {  
  52.         threadManager.getExecutorPool().execute(new Runnable() {  
  53.             @Override  
  54.             public void run() {  
  55.                 System.out.println("====4 test====");  
  56.             }  
  57.         });  
  58.     }  
  59. }  
  60.   
  61. import org.springframework.context.ApplicationContext;  
  62. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  63.   
  64. public class TestMain {  
  65.   
  66.     @SuppressWarnings("resource")  
  67.     public static void main(String[] args) {  
  68.         ApplicationContext atc = new ClassPathXmlApplicationContext("applicationContext.xml");  
  69.   
  70.         TestService3 t3 = (TestService3) atc.getBean("testService3");  
  71.         t3.test();  
  72.   
  73.         TestService4 t4 = (TestService4) atc.getBean("testService4");  
  74.         t4.test();  
  75.     }  
  76.   
  77. }  
0 0
原创粉丝点击