个人备忘
前言 :
在java中我们开辟一个线程要么继承 Thread 类,要么 实现Runable 接口,其实我们自己的new 出来的这个子类或者实现他们不是线程,他们只是一个普通的java 对象是会被GC 回收的。只不过我们在执行start() 之后,虚拟机会帮我们申请开辟一个新的线程,该线程通过我们告知的子类对象,去回调我们重写的run() 。所以我们的线程池不是在管理我们的java对象。而是管理cpu 开辟出来的这块资源。这样当我们再次new 子类的时候,放到我们的线程池中,cpu 将不会再次开辟新的资源。而是继续使用线程池中的开辟好的资源。
什么时候是线程池?
1. 降低资源的消耗,避免线程重复的创建和销毁造成的资源消耗。
2. 提高响应速度,任务:T1创建线程时间,T2任务执行时间,T3线程销毁时间。如果将线程存放到线程池中,那么T1和T2都可以提前处理,任务只有T2 的执行时间。
3. 提高线程的管理。
一 为什么我们要用线程池?
- 线程的容器,管理器。
- 工作线程做具体的任务。
- 对外提供任务接口,可以让我们的客户端提交任务到线程池。
- 任务的容器,当线程池满了,我们要有自己的任务容器用来暂时存储其他任务,DelayQueue<>、list/map 等线程集合或者队列。
二 实现一个自己的线程池
<!-- 配置线程池 -->
<bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 线程池维护线程的最少数量 -->
<property name="corePoolSize" value="2" />
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="10000" />
<!-- 线程池维护线程的最大数量 -->
<property name="maxPoolSize" value="5" />
<!-- 线程池所使用的缓冲队列 -->
<property name="queueCapacity" value="50" />
</bean>
private static void startThread() {
LOG.info("==>startThread");
threadPool.execute(new Runnable() {
public void run() {
try {
while (true) {
Thread.sleep(1000);
LOG.info("==>threadPool.getActiveCount():" + threadPool.getActiveCount());
LOG.info("==>threadPool.getMaxPoolSize():" + threadPool.getMaxPoolSize());
LOG.info("一秒间隔==>tasks.size():" + tasks.size());
// 如果当前活动线程等于最大线程,那么不执行
if (threadPool.getActiveCount() < threadPool.getMaxPoolSize()) {
LOG.info("==>tasks.size():" + tasks.size());
final NotifyTask task = tasks.take(); //使用take方法获取过期任务,如果获取不到,就一直等待,知道获取到数据
if (task != null) {
threadPool.execute(new Runnable() {
public void run() {
tasks.remove(task);
task.run(); // 执行通知处理
LOG.info("==>tasks.size():" + tasks.size());
}
});
}
}
}
} catch (Exception e) {
LOG.error("系统异常;", e);
}
}
});
}
三 线程池要做些什么?
- Execute 提交不需要返回值的任务。
- Submit 提交需要返回值的任务,返回值是个Futrue类型的对象,调用futrue的get方法来获取返回值。
四 提交任务
- ShutDown() : interrupt()方法来终止线程。
- ShutDownNow(),尝试停止所有正在执行的线程。
合理的配置线程池
- 线程数配置任务 :(1) cpu计算密集型,(2) IO密集型,混合型。
- (1) cpu 计算密集型 = 计算机cpu 个数 / 计算机cpu数+1 。这与操作系统有关,应付页缺失。ps : 空限度很高。
- 2) IO密集型 = 计算机cpu 个数 * 2 。
- 3)混合型 :拆分成计算密集型,IO密集型。
- 获取当前机器中的cpu核心个数:Runtime.getRuntime().availableProcessors() ; 可以用它 +1 或者 * 2 实现上面说的那两种类型。
- 一定要有有界队列,尽量不要使用无界队列。