virtual destructor()
将Base析构函数声明为virtual函数时,执行delete base ;语句就会删除subModel的对象;
exception
try catch
void operator new (size_t size,void pbuffer)
可以做某一个类的静态成员函数
参考:
https://www.toutiao.com/article/6956573052414984712/?wid=1670850368129
virtual destructor()
将Base析构函数声明为virtual函数时,执行delete base ;语句就会删除subModel的对象;
exception
try catch
void operator new (size_t size,void pbuffer)
可以做某一个类的静态成员函数
参考:
https://www.toutiao.com/article/6956573052414984712/?wid=1670850368129
bootstrap classloader
extension classloader
application classloader
custom classloader
双亲委派模型
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载
top 查看cpu使用率,重点关注:内核还是用户态、load值
cpu使用率2500%左右(40核系统,但平时才300%左右),并确认当前系统load值是否很高,如果很高(超过cpu核数),说明当前系统出现大量线程排队现象,如果load比较低但cpu很高,说明系统运行很顺畅,而是业务比较繁忙导致。
top -H pid 查看哪些线程cpu占比高
jstat -gc pid 查看java内部状态
jstack 查看调用stack
strace 查看系统调用
查看函数/接口耗时
调整jvm 内存参数,调整gc方式(cms->g1)
arthas
dashboard:当前系统的实时数据面板
thread:查看当前 JVM 的线程堆栈信息
jvm:查看当前 JVM 的信息
sc:查看JVM已加载的类信息
sm:查看已加载类的方法信息
jad:反编译指定已加载类的源码
classloader:查看classloader的继承树,urls,类加载信息,使用classloader去getResource
monitor:方法执行监控
watch:方法执行数据观测
trace:方法内部调用路径,并输出方法路径上的每个节点上耗时
stack:输出当前方法被调用的调用路径
tt:方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
reset:重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
quit:退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
shutdown:关闭 Arthas 服务端,所有 Arthas 客户端全部退出
memory 各种查看
netstat 查看timewait closewait, 查看数据包长什么样,是否符合预期等
equals VS ==
(1)对象类型不同(一个是object的成员方法,一个是操作符)
(2)比较的对象不同 一个是对象内容是否ok, 一个是引用或者地址是否ok
(3)执行速度不同
在每个类中,在重写equals方法的时侯,一定要重写hashcode方法。
根据Object规范,规范约定:
如果两个对象通过equals方法比较是相等的,那么它们的hashCode方法结果值也是相等的。
如果两个对象通过equals方法比较是不相等的,那么不要求它们的hashCode方法结果值是相等的。
当在一个应用程序执行过程中, 如果equals方法比较中没有修改任何信息,那么在同一个对象上重复调用hashCode方法时,它必须始终返回相同的值。但如果从一个应用程序到了另一个应用程序,两个应用程序汇中调用hashCode方法的返回值可以是不一致的。
https://cloud.tencent.com/developer/article/1856972
优点:
1.能够运行时动态地获取类的实例,提高灵活性
2.与动态编译结合
缺点:
1)使用反射性能较低,需要解析字节码,将内存中的对象进行解析。
解决方案:
1、通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
2、多次创建一个类的实例时,有缓存会快很多
3、ReflflectASM工具类,通过字节码生成的方式加快反射速度
2)相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
volatile 的三点:
(1)保证可见性( 主内存 VS JAVA内存)
(2)禁止指令重排
Instance = new Singleton();可以分为以下三步:
Memory = allocate();//1.分配对象内存空间
Instance(memory)//2.初始化对象
Instance = memeory //3.设置初始化的对象指向刚分配的内存地址,此时instacne ! =null
步骤2和步骤3不存在数据依赖关系,所以这种重排序是允许的
Memory = allocate();
Instance = memeory
Instance(memory)//2.初始化对象
所以这个时候出现的问题为多个线程在这里获得单例对象,第一个访问者在instance = new Singleton();这一步骤时由于指令重排序,底层先给对象分配好了地址,此时不为空,这个时候其他线程访问,instacne不为空,但是得不到实例对象。
(3)不保证原子性
volatile的应用场景
DCL(Double Check Lock双端检索机制)
双端检索机制不一定安全,原因是有指令重排序的存在,加入volatile可以禁止指令重排。 在某一个线程执行到第一次检测时,此时instance不为null,但是insatnce的引用对象可能没有初始化完成
如何保证原子性
这种问题可以使用synchronized 或者使用原子变量 来解决。原子变量通过调用unsafe类的cas方法实现了原子操作,由于CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许中断,也即是说CAS是一条原子指令,不会造成所谓的数据不一致的问题。
无锁-》偏向锁-》轻量级CAS自旋锁-》重量级锁
https://blog.csdn.net/weixin_45606067/article/details/126766885
区别如下:
1.Lock是显示锁(手动开启和关闭锁), synchronized时隐式锁,出来作用域自动释放
2.Lock只有代码块锁,synchronized有代码块锁和方法锁
3.使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供了更多子类)
4.lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;
5.异常是否释放锁:
synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。(所以最好将同步代码块用try catch包起来,finally中写入unlock,避免死锁的发生。)
6.是否响应中断
lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断;
7.是否知道获取锁
Lock可以通过trylock来知道有没有获取锁,而synchronized不能;
8.Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)
9.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
10.synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度
AQS
condtion是通过Reentlock的newCondtion方法创建出来的
rwlock也是基于AQS实现的读写锁
Semaphore 是一套单独的机制,用来实现信号量,多个线程共同访问一个资源。
euraka
robbin
hystrix
Zuul
config
Feign
在不侵入业务代码的情况下,实现日志打印、登录鉴权等功能。
动态代理技术,标准JDK动态代理 OR CGLIB代理
Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能。Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种XML、 JavaConfig、hin处理起来比较繁琐。于是为了简化开发者的使用,从而创造性地推出了Spring boot,约定优于配置,简化了spring的配置流程。说得更简便一些:Spring 最初利用“工厂模式”(DI)和“代理模式”(AOP)解耦应用组件。大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(一些用Spring 解耦的组件),用开发 web 应用( SpringMVC )。然后有发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了一些“懒人整合包”(starter),这套就是 Spring Boot。
Spring MVC的功能Spring MVC提供了一种轻度耦合的方式来开发web应用。Spring MVC是Spring的一个模块,式一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
inversion of control
DI 依赖注入
第三方容器来管理,底层实现是基于反射。
通过三个map(一级,二级,三级)创建中的对象数组
只能解决通过set + 单例模式; 无法解决:基于构造函数的循环依赖、通过set + 多例模式
给定数字N和M,你需要从数字1到N的序列中添加+或-,使得序列的和等于M。
打印出所有满足此关系的序列,例如,给定N=4 M=6,则满足条件得序列是1-2+3+4=6(一定存在此序列)
1 |
|
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖 一次 该股票可能获得的利润是多少?
例如一只股票在某些时间节点的价格为[9, 11, 8, 5, 7, 12, 16, 14]。
如果我们能在价格为5的时候买入并在价格为16时卖出,则能收获最大的利润11。
样例
输入:[9, 11, 8, 5, 7, 12, 16, 14]
输出:11
1 | class Solution { |
你需要知道的两个前置技巧:
双层定值拆分原则:当涉及两层循环时,可以将外层循环变量当成定值,对循环的整体结构进行整体审视,确定是否可以优化掉一层。 把外层变量当成定植之后,观察内层循环导致在干嘛。
最值计算的累积效应:当涉及最值计算时,减元素会让之前找到的的最值失效;而加元素只需要拿新加的元素与前最值比较即可
我们的优化,需要你知晓上面的两个技巧,然后做适当的启发式思考,具体过程我已经呈现在下面的注释中了。
1 | class Solution { |
那么,我们更换迭代顺序之后。
1 |
|