Java并发编程笔记一
Java个人学习笔记
背景
甲方项目提出前端页面增加一个功能,需要将数据库的100万(百万两级)条数据,在限定8秒之内(用户体验)导出到指定数量的Excel表.
采用方案一:C++或者golang或者C等等,但是后端技术栈是SpringClound微服务,这样胶水式操作不易维护。
采用方案二:Java操作,采用单线程一行一行的读取后写入Excel,那大概率会超时。
采用方案三:使用Java多线程。
分析项目需求 Java多线程不仅是实际项目需要的,还是面试笔试重点。
进程和线程
进程
进程可以理解为运行的一个程序(QQ,微信,网易音乐,Word,运行中的SpringBoot jar包),由PCB(进程控制块)、程序段、数据段组成。可以查看任务管理器重的进程如下
一个进程在OS中的资源,包含了CPU、内存、磁盘、网络、I/O等等。
OS支持多任务模型,会有类似上图 可以同时运行多个程序,对比多道程序概念。
每个进程生命周期都会有就绪态,运行态,阻塞态,新建态PCB,终止态五种状态,但前三种为基本态,时间占比较长。
一个进程至少包含一个线程(主线程)。
线程
一个进程的运行开销重,为了更好的使多道程序并发执行。
线程是CPU使用的基本单元,由线程ID、程序计数器、寄存器集合和栈组成。
进程由一个或多个线程组成:创建一个进程会伴随着创建一个线程(主线程)
调度切换:线程上下问切换比进程上下文切换快
创建进程:需要为进程划分一整块完整内存,需要大量初始化操作,比如要把内存分段(堆栈、正文区等)。
创建线程:只需要确定PC指针和寄存器的值,并且给线程分配一个栈用于执行程序,同一个进程的多个线程间可以复用堆栈。
一个进程可以划分为多线程(并发)的重要前提:通过线程之间的通信,保证数据原子性、可见性、有序性
原子性(atom)
一个或多个操作,要么全部执行且在执行过程中不被任何因素打断,要么全部不执行。在 Java 中,对基本数据类型的变量的读取和赋值操作是原子性操作。
保证原子性
- synchronized 关键字定义同步块或者同步方法保障原子性
- Lock接口保证原子性
- Atomic类型保障原子性
可见性
当一个线程修改了共享变量的值,其他线程能够看到修改的值
JMM通过共享内存实现线程通信
volatile变量和普通变量
volatile变量强行保证了被一个线程修改的变量的数据变量,被刷入内存。代码是一样的,所以其他线程也有volatile变量,但此时他们的volatile变量不生效
保证可见性
- volatile 关键字标记内存屏障保证可见性
- synchronized 关键字定义同步代码块或者同步方法保障可见性
- Lock接口保障可见性
- Atomic类型保障可见性
- final关键字保障可见性
有序性
程序执行的顺序按照代码的先后顺序执行
JVM存在指令重排,无关系的数据之间的初始,是没有顺序的。
1 |
|
如果上述有多个线程在执行,因为a和b之间在A中执行是无关联的,不同于B。 那么在A中经过指令重排序,可能先执行b = true;当还没执行a=a+2;时。另一个线程读取到b的true状态,拿着还是a=0;的情况就开始做a=a+1;
解决办法:使用volitile关键字 public int volitile a;
JMM(Java Memory Model,Java内存模型)
还有部分笔记后续补上,先赶项目去了。。。