大部分参考了尚硅谷–周阳的讲解视频,这里是整理
1、线程可见性
两个线程修改同一个对象,另一个线程能感知到
2、防止指令重排
场景:new Object()、懒汉式单例、DCL
单线程能确保最终结果和代码执行逻辑是一致的
3、不保证原子性
不会被中断的操作
自增++、自减-- 不是原子操作
使用技巧:用程序的强逻辑控制多个变量的读写,比如while、if等等
更多:如果在方法中创建一个子线程,访问方法中的创建的对象,是否会有可见性问题,如果是jdk自定义的对象,可以尝试将对象的创建过程放到当前类当中
Java Memory Model
1、加锁前必须把共享变量写回主内存
2、加锁前必须把主内存最新值读取到工作内存
3、加锁解锁是同一把锁
共享变量存在于主内存,但是线程操作的是工作内存,操作完成之后写会主内存。线程操作变量之前会先比较,
要求实现:1、可见性 2、原子性 3、有序性(指的jvm指令的有序性,不是代码的顺序执行)
原理:CAS操作系统原语支持,并非代码实现(可以用代码实现),JDK8后的线程安全的容器也是这个原理,JDK7的ConcurrentHashMap用的是分段锁(Segment)
ABA问题:不是所有场景都需要解决这个问题,原子类提供了版本号的参数getStamp
AtomicReference<V>
AtomicInteger常用方法:
getAndSet、getAndIncrement
使用场景:对于长耗时任务可以使用synchronized(比如申请资源,大对象、大文件操作、容量大的容器类操作),小而快的任务可以使用原子类
1、可重入(递归锁):可以一定程度上防止死锁
2、修饰this锁当前对象
3、修饰.class一般是静态类的锁
4、更有可能自己创建一个Object对象锁住
1、一个是关键字,一个是java接口
2、sychronzied只能是非公平的机制,Lock默认非公平但可以自己设置
3、两者都是可重入锁
4、Lock可以设置多个Condition,还可以精确唤醒,细粒度更高
5、synchronized是自动释放的锁,Lock需要手动释放
6、synchronized不能修饰变量,只能修饰方法和代码块
7、synchronized底层使用的monitor
8、Lock有超时获取和中断获取锁的方法
偏向锁:第一个线程访问共享变量时,就会打上这个标记,不会直接去拿重量级锁
轻量级锁(CAS):自旋10次以内,或执行时间短
重量级锁:
synchronized和ReentrantLock的默认情况都是非公平锁,就是指线程获取锁的时候允许插队(从其他状态恢复到RUNNABLE这一阶段),
一定是按照线程的创建顺序(这句话不对)
它在队列中的顺序去获取锁的(这个可以)
读锁共享,只要是读操作不会互相影响
写锁互斥,不管是前面有读的操作还是写的操作都会阻塞当前写的操作
在一个对象锁中尝试获取另一个对象的锁
排查命令:jps -l 找到进程号和对应类的全限定类名
jstack 进程号 打印堆栈信息,找到wait的字样,确定死锁
1、系统资源不足
2、资源分配不当
3、进程推进顺序不当
线程计数器,假设在父线程中启动了多个子线程,当这些子线程全部跑完再继续执行父线程的后续代码。
栅栏,线程数达到指定数量才会全部放出去运行
await、countDown
信号量,多个共享资源互斥使用:
等到占用资源的线程释放,被阻塞的线程还可以再次获取
acquire、release
如果我们将wait放在if当中
1、都需要抛出InterruptionException
2、都会让当前线程blocking
3、sleep不会释放锁,wait则会释放
1、用join就可以实现,但是join一定会等待子线程死掉以后才会开启另一个线程,如果对细粒度要求比较高,用它不划算,而且join一定是父子线程,线程多了嵌套会比较深。
1、继承线程类Thread
2、实现Runnable接口
3、实现Callable接口
4、使用线程池
底层就是阻塞队列
1、降低重复创建和销毁的性能消耗,也提高了响应速度
2、管理和调度起来方便
注意在finally中shutdown,否则停不下来
FixedThreadPool(size):固定线程数的线程池
CachedThreadPool():可扩容的
SingleThreadExecutor():单线程的
无论哪个,内部都会调用ThreadPoolExecutor构建
上述都是Executors创建出来的,正常情况生产上一个都不用。。。,原因是阻塞队列的长度是Integer.MAX_VALUE容造成OOM,我们使用ThreadPoolExcecutor去写线程池 ,代码:
BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(10);
ExecutorService threadPool = new ThreadPoolExecutor(3,
6,
1L,
TimeUnit.SECONDS,
blockingQueue,
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for(int i = 0; i < 17; i ++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 办理业务");
});
}
} finally {
threadPool.shutdown();
}
CPU的核数:Runtime.getRuntime().availableProcessors();
CPU密集型:CPU核数 + 1(减少线程切换CPU)
IO密集型:CPU核数 * 2 (IO并不一定在用CPU)或者 CPU核数 / (1-阻塞系数)
阻塞系数一般为 0.8~0.9
FutureTask只会被一个线程执行
无返回值和有返回值
FutureTask的get方法有超时获取
前五个:
corePoolSize:核心或常驻线程数
maximumPoolSize:最大线程数,当核心线程和阻塞队列都满了,才扩容,也就是说到达最大线程数才会触发拒绝策略
keepAliveTime:多余线程存活时间
TimeUnit:时间单位
BlockingQueue:阻塞队列,阻塞的是没能进入线程池的线程
后面两个:
threadFactory:创建线程的工厂(一般默认)
handler:拒绝策略,到达最大线程数且阻塞队列已满,触发
RejectedExceprionHandler
1、AbortPolicy(默认):直接抛异常
2、DiscardPolicy:直接丢弃任务
3、CallerRunsPolicy:回退给调用者线程
4、DiscardOldestPolicy:抛弃队列中等待最久的任务
BlockingQueue<T>
将变量与某一线程进行绑定
1、== 可以直接比较基本数据类型的值,如果不是基本类型,比较的是地址。
equals是Object类提供,可以被重写,如果没有重写调用的就是 ==
2、hashCode是内存地址转换的int值,没有重写过的则任何对象hashCode不相等。
一般重写eqauls也要重写hashCode
所以equals为false则hashCode可能相等,hashCode相等equals也不一定为true
地址与运算:equals、hashCode、
线程相关:wait、notify、notifyAll
常用:clone、toString
垃圾回收:finalize
Collection是列表的父接口
Collections提供了对列表和Map的操作方法
线程不安全、不能存null、会去重、无法保证输出顺序。
它的底层数据结构就是HashMap,HashSet的Value是不可变的PRESENT对象(Object),就是利用HashMap的key实现的
线程不安全,安全化的几种方式:
// Vector是线程安全的,读写都同步
List<T> list = new Vector<>();
// 只有写是同步的
List<T> list = Collections.synchronizedList(new ArrayList<>());
List<T> list = new CopyOnWriteArrayList<>();
内部的data数组是transient修饰的,因为它本身可以扩容,直接序列化内部数组,会有空的元素,增加了网络IO,自己序列化可以按照size准确输出想要的内容。
原理:读写分离的思想
常见异常 :
NullPointerException、
InterruptionException、
ConcurrentModificationException、
在普通循环中增删非线程安全集合的元素会有这个异常
IOException、
1、JDK8取消了永久代,使用元空间(本机物理内存)
spring框架注册bean的默认方式(singleton)
1、引用计数,难以解决循环依赖
2、复制算法(年轻代)s0和s1
3、标记清除
节约空间,容易造成碎片
4、标记整理(老年代)
移动对象需要成本
哪些可以作为GCRoots:
1、虚拟机栈(栈帧中的局部变量)中引用的对象
2、类静态属性引用对象
3、方法区中常量引用的对象(static final)
4、本地方法栈中的JNI(Native方法)引用的对象
有了这个就进行可达性分析
参数类型:(多个命令之间空格间隔)
1、标配参数,每个版本的java都会有:-version、-help、
2、X参数:-Xint解释执行、-Xcomp编译执行、-Xmixed混合执行
3、XX参数:
a、布尔类型:-XX:+PrintGCDetails
b、KV设值类型:-XX:属性key=属性值value
-XX:MetaspaceSize=512m(设置元空间大小)
c、jinfo举例:
jinfo -flag PrintGCDetails 进程号
jinfo -flag MetaspaceSize 进程号(21807104)
jinfo -flag MaxTenuringThreshold 进程号 (查看最大年龄)
-Xms等价于-XX:InitialHeapSize (Runtime.getRuntime().totalMemory())
-Xmx等价于-XX:MaxHeapSize (Runtime.getRuntime().maxMemory())
java -XX:+PrintFlagsInitial -version = 是默认的没改过的,:=是修改过的
java -XX:+PrintCommandLineFlags -version
常用参数列举:
-Xms:初始堆内存大小
-Xmx:最大堆内存大小
-Xss:栈内存大小(在windows下,用jinfo -flag ThreadStackSize查看是0,)
-Xmn:设置年轻代大小
-XX:MetaspaceSize 设置元空间大小
-XX:+PrintGCDetails 打印垃圾回收具体情况
-XX:SurvivorRatio 伊甸园区和幸存者区的比例(默认是8:1:1)
-XX:NewRatio 老生代和新年代占比 (默认2:1)
-XX:MaxTenuringThreshold 设置垃圾的最大年龄(默认15,只能修改为15及以下)
2:1
整体架构:
强引用:不会被回收,即使OOM。(Object o = new Object())
软引用(SoftReference):内存足够就不会回收,不足就会回收。通常用于缓存,加载图片
弱引用(WeakReference):内存充足也会被回收
虚引用(PhantomReference):任何时候都可能被回收,必须和ReferenceQueue一起使用,get永远是null
WeakHashMap<>
java.lang.StackOverflowError
递归次数过多
java.lang.OutOfMemoryError:Java heap space
对象过多、或者大对象(比如很大的字节数组)
java.lang.OutOfMemoryError:GC overhead limit exceeded
对象生产过多,多数时间用于GC,且回收了不到2%(比如容器中对象很多)
java.lang.OutOfMemoryError:Direct buffer memory
可能使用了堆外内存(ByteBuffer.allocateDirect(capability))速度快(nio)
java.lang.OutOfMemoryError:unable to create new native thread
线程创建过多,解决办法:
1、减少线程创建数量
2、修改linux配置(默认1024)
vim /etc/security/limits.d/90-nproc.conf
java.lang.OutOfMemoryError:Metaspace
静态类过多或者使用反射不断加载静态类
4种主要垃圾回收器:Serial(串行)、Parallel(并行)、CMS(并发标记回收)、G1、(ZGC)
Serial单线程回收,会暂停用户线程,不适合服务器
Parallel多线程回收,暂停时间缩短
CMS用户和垃圾回收可以交替执行不一定并行,不会暂停用户线程或者暂停时间很短
回收算法:
引用计数:
复制拷贝:新生代
标记清除:有内存碎片
标记整理:老年代
java -XX:+PrintCommandLineFlags -version
指定垃圾回收器:(-XX:+)
1、UseSerialGC,---------SerialOldGC(不再推荐)
相关名词:DefNew----Default New Generation、Tenured----Old这些词汇用+PrintGCDetails可以看到,分别指代的就是年轻代和老年代的GC回收器
2、(串行的多线程版)UseParNewGC,--------SerialOldGC(不再推荐)
相关名词:Parallel New Generation、Tenured
3、UseParallelGC,----------UseParallelOldGC,关注吞吐量(JDK8默认的方式)
相关名词:PSYoungGen----Parallel Scavenge、ParOldGen----Parallel Old Generation
4、UseConcMarkSweepGC,并发标记清除(针对老年代)
5、UseG1GC
四个回收步骤:
a、初始标记(CMS initial mark)会暂停用户线程
b、并发标记(CMS concurrent mark)和用户线程一起
c、重新标记(CMS remark)会暂停用户线程
d、并发清除(CMS concurrent sweep)和用户线程一起
解决内存碎片:-XX:CMSFullGCsBeforeCompaction 0(默认值是0)多少次GC会进行一次整理
6、UseG1GC
这个应该需要深入一点,暂不写粗制滥造的。
如何选择
单CPU或小内存,单机程序:+XX:UseSerialGC
多CPU,大吞吐量,后台计算型应用:-XX:+UseParallelGC或-XX:UseParrallelOldGC
多CPU,追求低停顿时间,快速响应如互联网应用:-XX:+UseConcMarkSweepGC或-XX:+ParNewGC
参数 | 新生代垃圾回收器 | 新生代算法 | 老年代垃圾回收器 | 老年代算法 |
---|---|---|---|---|
-XX:+UseSerialGC | SerialGC | 复制 | SerialOldGC | 标整 |
-XX:+UseParNewGC | ParNew | 复制 | SerialOldGC | 标整 |
-XX:+UseParallelGC/-XX:+UseParrallelOldGC | Parallel[Scavenge] | 复制 | ParallelOld | 标整 |
-XX:+UseConcMarkSweepGC | ParNew | 复制 | CMS + SerialOld的收集器组合(SerialOld作为CMS出错的后备收集器) | 标清 |
-XX:+UseG1GC | G1整体上采用标记-整理算法 | 局部是通过复制算法,不会产生内存碎片 |
启动命令: (nohup) java -server -Xms 10m -Xmx 10m -XX:+UseG1GC -jar … &
@ConfigurationProperties
既可以设置属性注入的前缀prefix,可以设置自定义的yml配置文件
@Bean
@Configuration
@EnableConfigurationProperties
@Component
public class BeanUtils implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void getBean(String name) {
return beanFactory.getBean(name);
}
}
IoC控制反转,是从容器角度的说法,将bean的创建和获取交给容器管理
DI依赖注入,从bean或者使用角度的说法,给某个属性注入对象
1、BeanFactoryAware----setBeanFactory(BeanFactory beanFactory)
2、InitializingBean----afterPropertiesSet()可以用于属性检查
3、InstantiationAwareBeanProcessor----postProcessBeforeInstantiation(Class> beanClass, String beanName)实例化Bean之前执行
----postProcessAfterInstantiation(Object bean, String beanName)实例化Bean之后执行
4、BeanPostProcessor----postProcessBeforeInitialization(Object bean, String beanName)
----postProcessAfterInitialization(Object bean, String beanName)
实际上就是一个Map的单例池,通过Type或者name找到这个对象。
REQUIRED(默认):加入当前事务
SUPPOTRS:有事务就支持,没有则不会开启
MANDATORY:
REQUIRES_NEW:每次都新开启一个事务,挂起当前事务
NOT_SUPPORTED:
NEVER:
NESTED:
@Transactional默认遇到异常会回滚
使用它的主要目的是给一系列对象增强一些相同的功能,比如日志、事务
切面(Aspect):一个关注点的模块化
连接点(Joinpoint):一个方法的执行
切入点(Pointcut):匹配连接点的断言,这个是关键
引入(Introduction):
目标对象(Target Object)
AOP代理(AOP Proxy)
织入(Weaving):
通知(Advice):即你想增强的功能
我自己想象的抽象视图:
INSERT INTO user (col1, col2, col3)
VALUES
<foreach collection="list" item="user" seperator=",">
(#{user.name}, #{user.password}, #{user.sex})
foreach>
insert>
可以从redis本身的特性回答:
1、key-value数据库中速度最快、综合排名最高,和前端的json对象结构一致
2、内存级的数据库访问速度快,尤其是读取速度
3、作为独立的中间件可以集群化,后期有分布式场景易扩展
第一范式:
列都是不可再分数据。
第二范式:
每个表只描述一件事
第三范式:
不存在对非主键列的传递依赖
count()、max()、min()、abs(x)、pi()、sqrt()、mod(x,y)、round、floor、ceil
concat、trim
show engines;
查看表emp的存储引擎:show create table emp;
MyISAM不支持事务和外键,select和insert速度快,不支持行级锁,默认使用表级锁
InnoDB支持事务,MySQL默认,有提交和回滚的能力,采用行级锁
MEMORY内存级别,速度快
MERGE一组MyISAM表的组合
数据定义语言DDL(Data Definition Language)
DDL
CREATE,DROP,ALTER
create table dept(
deptno int primary key,
dname varchar(20)) engine=myisam;
数据查询语言DQL(Data Query Language)
SELECT
数据操纵语言DML(Data Manipulation Language)
INSERT,UPDATE,DELETE
数据控制功能DCL(Data Control Language)
GRANT,REVOKE,COMMIT,ROLLBACK
db.opt:记录库的默认使用的字符集和校验规则
frm:表结构文件
ibd:数据文件
use databaseName;
create table tableName(
id int primary key,
name varchar(20),
age int) engine=innodb charset=utf8;
)
insert into tbl_name(col1,col2,col3,col_varname)
values(val1,val2,val3,@varname),
(val21,val22,val23,@varname),
(val31,val32,val33,@varname)
表级锁:
行级锁:
页面锁:
读未提交:(脏读)事务还未提交就可以访问已执行语句的结果
读已提交:(不可重复读)只能能读取已提交事务的结果,同一个事务两次selelct结果不一致
可重复读(MySQL默认的隔离级别):(幻读)同一个事务两次select结果的记录数不一致
串行化:(只能顺序执行的事务)
ACID:原子性(Atomicty)、一致性(Consistency)、隔离性(Lsolation)和持续性(Durability)
查看日志位置
show variables where variable_name=“log_error” or variable_name=“log_warnings”;
错误日志(error log)
通用查询日志(General query log)
show variables like “%general%”
二进制日志(binary log)
记录了对MySQL数据库执行的更改操作,并且记录了语句的发生时间、执行市场;但是它不记录select、show等不修改数据库的操作。主要用于数据库恢复和主从复制。
show variables like “%log_bin%”; // 查看是否开启
show variables like “%binlog%”; // 参数查看
show binary logs; // 查看日志信息
慢查询日志(Slow query log)
show variables like ‘%slow_query%’; // 是否开启
show variables like ‘%long_query_time%’; // 时长
CREATE UNIQUE INDEX 其余同上
只会按照左侧第一个建立索引的列进行扫描,只会在order by和group by这些语句中生效,和and的次序无关。
like 开头不
一代:
eureka:注册中心、拉模式、AP
hystrix:熔断器
ribbon:负载均衡
feign:hystrix + ribbon
gateway:网关
springcloud config:注册中心
二代:
nacos:注册中心、推模式、AP/CP
top:看CPU和内存占用
uptime:
vmstat:查看CPU
free:
df:
iostat:
ifstat:
pidstst:
不用重复简历里有的基本信息,直接说常用技术和最近的项目就可以。
一般问公司业务,会使用哪些技术框架,是否有完整且明确的晋升线路和技术培养方案,可以问一个项目会分配多少开发人员和项目紧急情况,从侧面观察公司规模、人事管理和是否加班等。
MyBatis现在应该不怎么问了,还有SpringMVC执行流程啥的,比较基础,但是仍然会考察java基本功,会深度化。
人工智能暂不了解。
该文档已经上传到gitee,前后整理耗时较长,后面会首先跟新gitee,再来补充博客。