工作这么多年,很少有时间写博客,昨天和一个正在跳槽找工作的同学交流,他是做web的,面试的时候被问到了线程池一块的技术,被难住了!这让我不禁也想巩固下我这方便的基础了,天天在用的东西,尤其是像我们这种做互联网服务端开发的,高并发处理中创建一个优异Thread Pool对线程进行复用还是很重要的!俗话说好记性不如烂笔头,先介绍下Executor接口吧!
为什么需要创建线程池:
(1)因为服务器如果每一个请求都会创建一个新线程,会导致性能上的瓶颈,因为线程创建和销毁都需要jvm不停的处理,如果一个线程执行的时间 < (线程创建时间+线程销毁的时间)的时候,我们就要考虑线程的复用了!
(2)、线程数量创建过多,没有有效的管理,反而起到的是副作用,会大大降低系统的性能的!
(3)、我们要根据具体的业务需求不同,结合操作系统的处理器CPU核数,能够合理的控制线程池大小!选择不同策略的线程池,盲目使用也会带来一定风险,比如内存泄漏,死锁,并发问题.....
线程池的好处:
(1)、降低资源消耗:线程复用。
(2)、提高响应速度:有任务的时候,不需要去等待创建线程,直接使用已有的线程;
(3)、管理:线程池对线程进行统一分配,调优,监控等等;
一、Executor 接口 (友情提示:不是类Executors)
线程与Executor框架线程,操作系统各自扮演的角色:任务的2级调度
java.util.concurrent.Executor: 大部分线程池相关的接口都是实现这个接口的
public interface Executor {
void execute(Runnable command);
}
他的子接口和实现的类如下:
完整的Executor接口继承实现结构图如下:
我们重点看我圈出来的不分,基本就是你学习线程池这块要反复看的内容;
我们继续顺着源代码往下分析:(绿色实线箭头是继承,虚线是接口实现)
1、ExecutorService:servirce顾名思义是提供服务的接口。
【首先申明executor架构下的ForkJoinPool思想和其他的接口类不一样,ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来;(后续具体介绍ForkJoinPool用法)】;
(1)shutdown: 具体源码实现是:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//想操作shutdown和shutdownnow权限check ModifyThread权限通过
checkShutdownAccess();
//将runstate设为给定的目标
advanceRunState(SHUTDOWN);
//中断一些正在等待任务的的空闲的线程,
interruptIdleWorkers();
//取消和清楚,由于shutdown策略中所有不应该继续运行的工作队列
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
下面我谢的一个简单的test:
总结:shutdown 调用之后,线程池拒绝接受新submit的任务,但是会继续运行在shutdown之前的任务;
(2)、shutdownNow:源码相似,他是停止正在运行的任务,返回空闲的线程,并且拒绝接受新的任务
(3)、isShutdown():当前executor是否已经shutdown
(4)、isTerminated();若关闭后所有任务都已完成,则返回true。注意除非首先调用shutdown或shutdownNow,否则isTerminated永不为true;
(6)、submit():提交新的任务,任务分Runnable和Callable类型
(7)、invokeAll()和invokeAny(),在批量执行或多选一的业务场景中非常方便。invokeAll()在所有任务都完成(包括成功/被中断/超时)后才会返回,invokeAny()在任意一个任务成功(或ExecutorService被中断/超时)后就会返回。
package com.executor.test;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* User: ZhuRong
* Date: 2018-07-20 13:18
*/
public class ShutDowmTest {
static int index = 1;
public static void main(String[] args) {
try {
//创建一个线程池,可以同一时间容乃3条线程
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new AutoIncressNum());
}
Thread.sleep(2000L);
executorService.shutdown();
for (int i = 0; i < 3; i++) {
executorService.submit(new AutoIncressNum());
}
System.out.println(executorService.isShutdown());
System.out.println(executorService.isTerminated());
} catch (Exception e) {
e.printStackTrace();
}
}
static class AutoIncressNum implements Runnable {
@Override
public void run() {
try {
Random random = new Random();
Thread.sleep(1000L + random.nextInt(5000));
System.out.println(Thread.currentThread().getName()+":"+index);
index++;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + " Interrupted!");
e.printStackTrace();
}
}
}
}
package com.executor.test;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* User: ZhuRong
* Date: 2018-07-20 13:18
*/
public class ShutDownNowTest {
static int index = 1;
public static void main(String[] args) {
try {
//创建一个线程池,可以同一时间容乃3条线程
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new AutoIncressNum());
}
Thread.sleep(2000L);
List list = executorService.shutdownNow();
System.out.println(executorService.isShutdown());
System.out.println(executorService.isTerminated());
for(Runnable l: list){
System.out.println(l.toString());
}
for (int i = 0; i < 2; i++) {
executorService.submit(new AutoIncressNum());
}
} catch (Exception e) {
// e.printStackTrace();
}
}
static class AutoIncressNum implements Runnable {
@Override
public void run() {
try {
Random random = new Random();
Thread.sleep(1000L + random.nextInt(5000));
System.out.println(Thread.currentThread().getName()+":"+index);
index++;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + " Interrupted!");
e.printStackTrace();
}
}
}
}
先介绍这2个接口,后面有时间继续介绍其他的线程池相关的接口和类!这个测试案例建议和大家还是跑一跑就懂了ExecutorService这一个接口的里面的api应用了!