推荐学习
- 接招吧!最强“高并发”系统设计 46 连问,分分钟秒杀一众面试者
- 这是什么神仙面试宝典?半月看完25大专题,居然斩获阿里P7offer
- 牛掰!“基础-中级-高级”Java程序员面试集结,看完献出我的膝盖
01 前言
本章节主要分享下,多线程并发在电商系统下的应用。主要从以下几个方面深入:线程相关的基础理论和工具、多线程程序下的性能调优和电商场景下多线程的使用。
02 多线程
2.1 JU·C线程池
(1)概念
回顾线程创建的方式
- 继承Thread
- 实现Runnable
- 使用FutureTask
线程状态
NEW:刚刚创建,没做任何操作
RUNNABLE:调用run,可以执行,但不代表一定在执行(RUNNING,READY)
WATING:使用了waite(),join()等方法
TIMED_WATING:使用了sleep(long),wait(long),join(long)等方法
BLOCKED:抢不到锁
TERMINATED:终止
线程池基本概念
根据上面的状态,普通线程执行完,就会进入TERMINA TED销毁掉,而线程池就是创建一个缓冲池存放线程,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等候下次任务来临,这使得线程池比手动创建线程有着更多的优势:
- 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
- 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
- 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM
- 节省cpu切换线程的时间成本(需要保持当前执行线程的现场,并恢复要执行线程的现场)。
- 提供更强大的功能,延时定时线程池。(Timer vs ScheduledThreadPoolExecutor)
常用线程池类结构
说明:
- 最常用的是ThreadPoolExecutor
- 调度用的ScheduledThreadPoolExecutor
- Executors是工具类,协助创建线程池
(2)工作机制
在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程。一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
线程池状态
- RUNNING:初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0。RUNNING状态下,能够接收新任务,以及对已添加的任务进行处理。
- SHUTDOWN:SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
//shutdown后不接受新任务,但是task1,仍然可以执行完成
ExecutorService poolExecutor = Executors.newFixedThreadPool(5);
poolExecutor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
System.out.println("finish task 1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
poolExecutor.shutdown();
poolExecutor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("ok");
- STOP:不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。调用线程池的shutdownNow()接口时,线程池由(RUNNING 或SHUTDOWN ) -> STOP
//改为shutdownNow后,任务立马终止,sleep被打断,新任务无法提交,task1停止
poolExecutor.shutdownNow();
- TIDYING:所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING。线程池变为TIDYING状态时,会执行钩子函数terminated(),可以通过重载terminated()函数来实现自定义行为
//自定义类,重写terminated方法
public class MyExecutorService extends ThreadPoolExecutor {
public MyExecutorService(int corePoolSize, int maximumPoolSize, long
keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue);
}
@Override
protected void terminated() {
super.terminated();
System.out.println("treminated");
}
//调用 shutdownNow, ternimated方法被调用打印
public static void main(String[] args) throws InterruptedException {
MyExecutorService service = new
MyExecutorService(1,2,10000,TimeUnit.SECONDS,new
LinkedBlockingQueue<Runnable>(5));
service.shutdownNow();
}
}
- TERMINA TED:线程池处在TIDYING状态时,执行完terminated()之后,就会由TIDYING ->TERMINA TED