1 概述
池化是常见的思想,线程池是非常典型的池化的实现,《Java并发编程实战》也大篇幅去讲解了Java中的线程池。本文实现一个简单的线程池。
2 核心类
【1】接口定义
[java] view plain copy
print
?
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 ?
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. 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. 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. new Worker();
45. worker.start();
46. workers.add(worker);
47. }
48. // 添加关闭钩子
49. 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. "addNum too large");
79. }
80. }
81.
82. @Override
83. public void reduceWorkers(int reduceNum) {
84. if ((workers.size() - reduceNum <= 0))
85. "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. null;
109. // 加锁(若只有一个woker可不必加锁,那就是所谓的单线程的线程池,线程安全)
110. synchronized (tasks) {
111. // 任务队列为空
112. while (tasks.isEmpty()) {
113. try {
114. // 阻塞,放弃对象锁,等待被notify唤醒
115. tasks.wait();
116. "block when tasks is empty");
117. catch (InterruptedException e) {
118. e.printStackTrace();
119. }
120. }
121. // 不为空取出任务
122. job = tasks.removeFirst();
123. "get job:" + job + ",do biz");
124. job.run();
125. }
126. }
127. }
128.
129. public void shutdown() {
130. false;
131. }
132. }
133. }
放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用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
?
1. public class TestService1 {
2. public static void main(String[] args) {
3. // 启动10个线程
4. new XYThreadPool<Runnable>(10);
5. new Runnable() {
6. @Override
7. public void run() {
8. "====1 test====");
9. }
10. });
11. }
12. }
13.
14. public class TestService2 {
15. public static void main(String[] args) {
16. // 启动10个线程
17. new XYThreadPool<Runnable>(10);
18. new Runnable() {
19. @Override
20. public void run() {
21. "====2 test====");
22. }
23. });
24. }
25. }
4 控制线程总数
希望在项目中所有的线程调用,都共用1个固定工作者数大小的线程池。
[java] view plain copy
print
?
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. 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. new Runnable() {
34. @Override
35. public void run() {
36. "====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. new Runnable() {
53. @Override
54. public void run() {
55. "====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. new ClassPathXmlApplicationContext("applicationContext.xml");
69.
70. "testService3");
71. t3.test();
72.
73. "testService4");
74. t4.test();
75. }
76.
77. }