从new对象感受JVM体系
前情概要对象的结构
对象头:
Mark Word:存储对象自身运行时的数据,如哈希码、GC分代年龄、锁状态标志
类型指针:知道是哪个类的实例,指向Class对象
实例数据:存储Java类中各个类型的字段,包括基本类型和引用类型
对齐填充:无意义,对象分配的内存是 8byte 的整数倍
对象创建的代码1Person person = new Person();
执行以上代码的时候,会经历以下几个步骤:
类加载
实例化
初始化
引用赋值
类加载如果在方法区的运行时常量池没有找到Person类的符号引用,那么就会进行类加载,类加载器就会把Person.class文件经过三大步后加载到JVM内存(运行时数据区的运行时常量池)。
类加载器Person类信息一开始保存在一个Person.java文件,经过编译之后生成对应的Person.class文件,类加载器就会把Person.class文件加载进JVM内存,同时在堆内存中生成相应的Class对象。
一般有三种重要的类加载器:
启动类加载器:C++实现,默认类都会被它所加载,避免核心类冲突
扩展类加载器:
应用类加载器:加载c ...
简单了解线程安全
线程安全对象的状态:对象状态不只和自身有关,还可能和自身的元素有关,如HashMap和内部的Entry
线程安全就是程序能够在多线程下正确的执行,如果在多线程执行某段代码出现错误,以下几个方面都可能影响线程安全:
变量可共享
变量可修改
访问修改变量是否使用同步机制
竞态条件当代码的正确性需要取决于多线程的执行时序的时候,就会发生竞态条件,此时结果是不确定的。
通常是先检查再修改的情况,如 i++、或者对象延迟初始化(先判断对象为null,然后创建对象)。
合理使用synchronized我们可以用synchronized限制临界区代码被多线程同时访问,但是同时也会有一些问题:
线程安全类的不安全使用:如先检查vector集合内是否有某个元素,没有进行添加,虽然vector是线程安全类,但是方法组合同样会发生竞态条件
性能问题:锁的粒度太大,直接对整个方法加锁;或者在一些耗时较长的地方加锁(如I/O等)
简单了解线程池
本文参考
Java线程池实现原理及其在美团业务中的实践 (qq.com)
硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理 | Throwable (throwx.cn)
池化思想线程池运用了池化的思想,类似的还有连接池、对象池,具有以下的一些好处:
减少线程创建、销毁的损耗
更快的响应任务请求
更好的管理线程以及监控线程
线程池创建方式ExecutorsExecutors类的四种JDK定义好的线程池:底层还是封装的ThreadPoolExecutor
主要的区别就在于线程数和队列的配置,无论是哪种都会有OOM的风险(线程数过多或者队列的任务过多)
SingleThreadPool:单实例的线程池
FixedThreadPool:SingleThreadPool的多线程版本
CachedThreadPool:不能把任务暂存到同步队列
ScheduledThreadPool:根据任务放入时间先后,存储任务到堆中,不断从堆顶取任务
ThreadPoolExecutor顶层父接口Executor只定义了一个方法execute()用于执行任务,Ex ...
AOP
什么是AOP?在AOP(面向切面编程)之前,不得不提一下OOP(面向对象编程),OOP把业务中的一些实体进行抽象封装,可以更加清晰的处理任务;但同时也有不足,无法定义横向的关系,如那些与业务无关的方法,这就需要AOP辅助,进行拓展,如一些日志功能的编写,可以减少大量代码冗余,减少模块的耦合度。
关于AOP的一些基础概念:
其实就是开启代理功能,同时定义切面类,以及编写切面类内部的切点以及通知
JoinPoint连接点:Spring把所有方法都看作连接点
PonitCut切点:需要被增强的方法
Advice通知:具体的增强行为
Aspect切面:通常是一个类,切点和通知的组合,Spring里面用Advisor表示
Target目标对象:被增强的方法的类的实例化对象
Weaving织入:将通知与切点整合,在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理
Proxy代理:用代理对象执行增强方法,可以用JDK或者CGLIB创建代理对象
五种Advice通知
Before advice(前置通知):切点前面执行,不能终止后续流程,除非抛异常
After returning adv ...
子数组和target
子数组的和或者乘积==target可以考虑这两种办法:前缀和+哈希表、滑动窗口
滑动窗口
有限制条件,每个元素都是正数,并且可以找到明确的窗口移动条件
前缀和+哈希表
一般都能用,注意是和不是乘积
简单了解ThreadLocal
什么是ThreadLocal?ThreadLocal是线程变量,每个线程可以在一个ThreadLocal里面存放一个变量,这个变量是线程安全的,除了ThreadLocal还可以用栈的本地变量或者锁来保证线程安全,并且可以用于方法间的数据传递。
ThreadLocalMap是ThreadLocal的一个内部类,用于保存数据,key是ThreadLocal的一个弱引用(可以有很多个ThreadLocal),那如果是强引用就不会被回收了,value是存放的变量值
12345// 强引用ThreadLocal<Object> threadLocal = new ThreadLocal<>();threadLocal.get();// 弱引用new ThreadLocal<>().get();
Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,也就是说每个线程有自己的ThreadLocalMap
简单来说,ThreadLocal本身不存储值,而是ThreadLocalMap存储值,每个线程一个T ...
简单了解三级缓存解决循环依赖
什么是循环依赖问题?Spring框架有个特点就是大量使用缓存,当Spring需要某个bean对象的时候,它不会直接创建这个bean,而是会先从缓存里面找,如果缓存中没有才会创建这个bean对象,比如Person对象有个Car属性,当Person对象属性赋值的时候就会去容器(缓存)里面拿,那么如果Car对象又有个Person属性,就会不断地重复这个过程,Person获取Car,Car又获取Person,最终方法无限递归造成栈溢出。
有什么办法进行属性赋值?在Spring可以通过构造器或者set()方法进行属性赋值,又分为byName(如@Resource)或者byType(如@Autowired)。
Spring能够解决的只能解决单例bean和set()方法注入的循环依赖。
单例bean和多例beanSpring是用了三级缓存存放提前暴露的半成品bean
而对于多例bean,没有使用缓存所以当Spring遇到多例bean的循环依赖将会直接抛出异常
set()方法和构造器set()方法是属性赋值使用的办法,配合反射实现
构造器在对象实例化的时候被调用,将会调用getBean属性赋值,但是这 ...
简单了解main启动发生了什么
前期编译那我们一开始是写了很多的.java文件嘛,java是一个编译 + 解释的语言,前期编译把这些**.java文件转换成字节码文件**,也就是.class文件。
后期编译和类加载在调用某个方法的时候,执行引擎会把.class字节码逐行解释为机器码(二进制的机器码才能让计算机执行,同时这里是JVM翻译的,不同的操作系统有不同适配的JVM,这也是Java可移植性的保证),当然解释型(如Java)是没有编译型的效率高的(如C、C++),那Java在这里也会进行了优化,对于热点代码,有即时编译器JIT进行优化(把这块热点代码直接翻译成机器码),同时对线程(操作系统分配有一定的栈空间)每次方法调用生成对应的栈帧,一般存放一些临时变量,这些临时变量如果是引用类型可能指向堆内存的对象。
类是懒加载的,需要的时候才会被加载进内存,类加载器会把这些.class文件加载进内存(加载、连接、初始化),其实也就是一些类的基本信息(如属性、方法、构造器等)放到方法区,同时在堆内存生成一个对应的Class对象指向方法区的某块保存着这个类信息的区域,后期我们在需要获取类信息或者是实例化对象的时候就可以通过访问C ...
位运算的一些想法
判断奇偶数:x % 2 == 0,可以替换成:x & 1 == 0,像HashMap在计算索引的时候就是这么干的
需要修改二进制数某一bit位的:ans |= x >> 1 就是修改低位开始的第二位
HTTP不同版本的区别
HTTP1.1HTTP1.1相对于HTTP1.0的优化
请求使用长连接代替短链接,不必每次请求都进行三次握手建立TCP连接,减少性能损耗(创建销毁进程)同时加快响应速度(没有慢启动、握手时延)
支持并发传输,不用等前一个请求收到响应,就可以发送请求,最大请求数据量可以到发送窗口的上限
HTTP1.1有什么不足?
请求头部未经压缩数据量大:影响传输延时
请求头部字段冗余:每次请求浪费较多
HTTP队头阻塞:服务端按照请求的顺序响应,如果服务端响应慢,可能有HTTP队头阻塞
单向请求:只有由客户端发送请求,服务端响应请求
HTTP2HTTP2相对于HTTP1.1的优化
头部压缩:如果同时发送多个请求,通信双方有一张头信息表,只需要发送索引,可以找到对应的头部字段
二进制数据:头部和数据部分都换成二进制存储,减少传输的大小,同时对计算机友好,不用进行转换,提高解析效率
并发传输:HTTP1.1没有对请求或者响应进行区分,所以只能要求服务端顺序响应,否则服务端响应的数据客户端无法组装(会组装不同请求的响应数据到一起),在HTTP2将每个HTTP请求或者响应封装成一个Stream,每个Str ...