发表时间:2022-03-25来源:网络
jdk是Java开发工具,包括jre和编译运行工具
jre是Java程序的运行环境
对于基本类型来说,只有==可以使用,用于比较数值是否相等
对于引用类型来说, ==比较引用地址,equals默认实现和等号一样,重写后根据重写规则比较两个对象是否相等。
规则:重写equals方法必须重写hashcode
两个对象相等,则hashcode必须相等两个对象不等,则hashcode可等可不等两对象hashcode相同(哈希冲突),对象可等可不等两对象hashcode不同,对象一定不相等round()方法在实现四舍五入的时候实际上是不论正负的,它会先将这个数加上0.5然后在像下取整。-1.5+0.5 = -1.0,向下取整为-1.
基础数据类型有:char、byte、short、int、long、float、double、boolean
抽象类的实现是继承关系,是一个 "是不是"的关系,而接口实现则是 "有没有"的关系。比如狗是否能钻火圈,能则可以实现这个接口,不能就不实现这个接口。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

1、java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
List,Set,Queue接口都继承Collection。
直接实现该接口的类只有AbstractCollection类,该类也只是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类。
2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
HashTable类和HashMap用法几乎一样,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低。
版本不同:HashMap-JDK1.2 Hashtable-JDK1.0HashMap继承AbstractMap实现Map接口;Hashtable继承Dictionary实现Map接口HashMap允许key或value为null,但是key为null只允许有一个;Hashtable不予许出现nullHashMap线程不同步;Hashtable线程同步如果你需要得到一个有序的结果时就应该使用TreeMap(因为HashMap中元素的排列顺序是不固定的)。除此之外,由于HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap。
底层使用HashMap实现,存入元素作为HashMap的key。
ArrayList是动态数组实现,LinkedList是用双向链表实现。
1、Vector是线程安全的,ArrayList不是线程安全的。
2、ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。
关于线程安全,同样的类似关系的类还有HashMap和HashTable,StringBuilder和StringBuffer,后者是前者线程安全版本的实现。
Array([])容量固定,确定后无法改变
ArrayList可以自动扩容
queue中没有元素时,poll返回null,remove抛异常
首先说一下迭代器模式,它是 Java 中常用的设计模式之一。用于顺序访问集合对象的元素,无需知道集合对象的底层实现。
Iterator 是可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。
缺点是增加新的集合类需要对应增加新的迭代器类,迭代器类与集合类成对增加。
使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
红黑树是一种自平衡的二叉查找树,Java的TreeMap和HashMap等都基于红黑树实现。
每个节点是黑色或者红色根节点是黑色每个叶子节点是黑色如果一个节点是红色,他的子节点必须是黑色从任意一个节点到叶子节点,经过的黑色节点数量相等如果不平衡,二叉树可能是瘸腿的,退化成链表,复杂度达到O(n)。
从根到叶子最长深度不超过最短深度的两倍。所以高度h<=2log(n+1),查找时间复杂度O(logN)
红黑树是近似平衡,并不是严格平衡,所以在维护平衡的成本上比AVL树要低。插入删除查找各种操作的性能相对比较稳定,所以工程上应用较多。
守护线程(即daemon thread),是个服务线程,比如负责垃圾回收的线程。
通过start()方法来启动的新线程,处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行相应线程的run()方法。
方法原型:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { // 省略... } corePoolSize执行ThreadPoolExcutor的execute方法,可能会遇到以下情况:
如果线程池中的线程数未达到核心线程数,则创建核心线程处理任务。如果线程数大于或者等于核心线程数,则将任务加入任务队列中,线程池中的空闲线程会不断的从任务队列中取出任务进行处理。如果任务队列满了,并且线程数没有达到最大线程数,则创建非核心线程去处理任务。如果线程数超过了最大线程数,则执行上面提到的几种饱和策略。线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。
RUNNINGJMM是Java内存模型,是一种虚拟机规范,规范了虚拟机与计算机内存如何协同工作,用于屏蔽各种硬件和操作系统的内存访问差异,让java程序在各种平台上都达到一致的并发效果。
线程安全问题体现在:
原子性:一个或多个操作在CPU执行过程中不被中断。线程切换会导致原子性问题。Java Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题。
可见性:一个线程对共享变量的修改,另一个线程能够立刻看到。缓存会导致可见性问题。synchronized、LOCK、volatile,可以解决可见性问题。
有序性:程序执行顺序按照代码的先后顺序执行。编译优化会导致有序性问题。Happens-Before规则可以解决有序性问题。Happens-before是JMM面向程序设计者提供的规则保证。
锁的升级过程:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁
synchronized用的锁存在对象头里,对象头有threadid字段。
第一次访问时字段为空,jvm使其持有偏向锁,并将threadid设置为线程id再次进入时会判断threadid是否与其线程id一致,一致则直接使用,如果不一致则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁如果执行一段时间后还没有获取到对象,或者这时候又有第三个线程来竞争锁,则将轻量级锁升级为重量级锁如果一组进程中的每个进程都在等待一个事件,而这个事件只能由该组中的另一个进程触发,导致所有进程都无限期等下去,这种情况会导致死锁。
举例:当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
资源死锁可能出现的情况主要有:
互斥条件:每个资源都被分配给了一个进程或者资源是可用的保持和等待条件:已经获取资源的进程被认为能够获取新的资源不可抢占条件:分配给一个进程的资源不能强制的从其他进程抢占资源,它只能由占有它的进程显示释放循环等待:死锁发生时,系统中一定有两个或者两个以上的进程组成一个循环,循环中的每个进程都在等待下一个进程释放的资源。总结方法:在并发程序中,避免了逻辑中出现复数个线程互相持有对方线程所需要的独占锁的的情况,就可以避免死锁。
ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。
如上文所述,ThreadLocal 适用于如下两种场景:
每个线程需要有自己单独的实例实例需要在多个方法中共享,但不希望被多线程共享synchronized关键字最主要有以下3种应用方式,下面分别介绍
修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁修饰静态方法,作用于当前类class对象加锁,进入同步代码前要获得当前类对象的锁修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁同步方法通过ACC_SYNCHRONIZED关键字隐式的对方法进行加锁。当线程要执行的方法被标注上ACC_SYNCHRONIZED时,需要先获得锁才能执行该方法。
同步代码块通过monitorenter和monitorexit执行来进行加锁。当线程执行到monitorenter的时候要先获得所锁,才能执行后面的方法。当线程执行到monitorexit的时候则要释放锁。
底层是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层的操作系统的Mutex Lock(互斥锁)来实现的。
两者都是锁,用来控制并发冲突,区别在于Lock是个接口,提供的功能更加丰富,除此之外,他们还有如下区别:
synchronize自动释放锁,而Lock必须手动释放,并且代码中出现异常会导致unlock代码不执行,所以Lock一般在Finally中释放,而synchronize释放锁是由JVM自动执行的。Lock有共享锁的概念,所以可以设置读写锁提高效率,synchronize不能。(两者都可重入)Lock可以让线程在获取锁的过程中响应中断,而synchronize不会,线程会一直等待下去。lock.lockInterruptibly()方法会优先响应中断,而不是像lock一样优先去获取锁。Lock锁的是代码块,synchronize还能锁方法和类。ReentrantLock实现了Lock接口
Atomic类是通过无锁(lock-free)的方式实现的线程安全(thread-safe)访问。它的主要原理是利用了CAS:Compare and Set。
CAS是指,在这个操作中,如果AtomicInteger的当前值是prev,那么就更新为next,返回true。如果AtomicInteger的当前值不是prev,就什么也不干,返回false。通过CAS操作并配合do … while循环,即使其他线程修改了AtomicInteger的值,最终的结果也是正确的。
Atomic类中,值是存在一个volatile的int里面。volatile只能保证这个变量的可见性。不能保证他的原子性。如何保证原子性:自旋 +CAS(乐观锁)。在这个过程中,通过compareAndSwapInt比较更新value值,如果更新失败,重新获取旧值,然后更新。
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
64.jsp 和 servlet 有什么区别?
65.jsp 有哪些内置对象?作用分别是什么?
66.说一下 jsp 的 4 种作用域?
67.session 和 cookie 有什么区别?
68.说一下 session 的工作原理?
69.如果客户端禁止 cookie 能实现 session 还能用吗?
70.spring mvc 和 struts 的区别是什么?
71.如何避免 sql 注入?
72.什么是 XSS 攻击,如何避免?
73.什么是 CSRF 攻击,如何避免?
90.为什么要使用 spring?
91.解释一下什么是 aop?
92.解释一下什么是 ioc?
93.spring 有哪些主要模块?
94.spring 常用的注入方式有哪些?
95.spring 中的 bean 是线程安全的吗?
96.spring 支持几种 bean 的作用域?
97.spring 自动装配 bean 有哪些方式?
98.spring 事务实现方式有哪些?
99.说一下 spring 的事务隔离?
100.说一下 spring mvc 运行流程?
101.spring mvc 有哪些组件?
102.@Re 的作用是什么?
103.@Autowired 的作用是什么?
104.什么是 spring boot?
105.为什么要用 spring boot?
106.spring boot 核心配置文件是什么?
107.spring boot 配置文件有哪几种类型?它们有什么区别?
108.spring boot 有哪些方式可以实现热部署?
109.jpa 和 hibernate 有什么区别?
110.什么是 spring cloud?
111.spring cloud 断路器的作用是什么?
112.spring cloud 的核心组件有哪些?
113.为什么要使用 hibernate?
114.什么是 ORM 框架?
115.hibernate 中如何在控制台查看打印的 sql 语句?
116.hibernate 有几种查询方式?
117.hibernate 实体类可以被定义为 final 吗?
118.在 hibernate 中使用 Integer 和 int 做映射有什么区别?
119.hibernate 是如何工作的?
120.get()和 load()的区别?
121.说一下 hibernate 的缓存机制?
122.hibernate 对象有哪些状态?
123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
124.hibernate 实体类必须要有无参构造函数吗?为什么?
125.mybatis 中 #{}和 ${}的区别是什么?
126.mybatis 有几种分页方式?
127.RowBounds 是一次性查询全部结果吗?为什么?
128.mybatis 逻辑分页和物理分页的区别是什么?
129.mybatis 是否支持延迟加载?延迟加载的原理是什么?
130.说一下 mybatis 的一级缓存和二级缓存?
131.mybatis 和 hibernate 的区别有哪些?
132.mybatis 有哪些执行器(Executor)?
133.mybatis 分页插件的实现原理是什么?
134.mybatis 如何编写一个自定义插件?
135.rabbitmq 的使用场景有哪些?
136.rabbitmq 有哪些重要的角色?
137.rabbitmq 有哪些重要的组件?
138.rabbitmq 中 vhost 的作用是什么?
139.rabbitmq 的消息是怎么发送的?
140.rabbitmq 怎么保证消息的稳定性?
141.rabbitmq 怎么避免消息丢失?
142.要保证消息持久化成功的条件有哪些?
143.rabbitmq 持久化有什么缺点?
144.rabbitmq 有几种广播类型?
145.rabbitmq 怎么实现延迟消息队列?
146.rabbitmq 集群有什么用?
147.rabbitmq 节点的类型有哪些?
148.rabbitmq 集群搭建需要注意哪些问题?
149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
151.rabbitmq 对集群节点停止顺序有要求吗?
152.kafka 可以脱离 zookeeper 单独使用吗?为什么?
153.kafka 有几种数据保留的策略?
154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
155.什么情况会导致 kafka 运行变慢?
156.使用 kafka 集群需要注意什么?
157.zookeeper 是什么?
158.zookeeper 都有哪些功能?
159.zookeeper 有几种部署模式?
160.zookeeper 怎么保证主从节点的状态同步?
161.集群中为什么要有主节点?
162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
163.说一下 zookeeper 的通知机制?
164.数据库的三范式是什么?
165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
166.如何获取当前数据库版本?
167.说一下 ACID 是什么?
168.char 和 varchar 的区别是什么?
169.float 和 double 的区别是什么?
170.mysql 的内连接、左连接、右连接有什么区别?
171.mysql 索引是怎么实现的?
172.怎么验证 mysql 的索引是否满足需求?
173.说一下数据库的事务隔离?
174.说一下 mysql 常用的引擎?
175.说一下 mysql 的行锁和表锁?
176.说一下乐观锁和悲观锁?
177.mysql 问题排查都有哪些手段?
178.如何做 mysql 的性能优化?
179.redis 是什么?都有哪些使用场景?
180.redis 有哪些功能?
181.redis 和 memecache 有什么区别?
182.redis 为什么是单线程的?
183.什么是缓存穿透?怎么解决?
184.redis 支持的数据类型有哪些?
185.redis 支持的 java 客户端都有哪些?
186.jedis 和 redisson 有哪些区别?
187.怎么保证缓存和数据库数据的一致性?
188.redis 持久化有几种方式?
189.redis 怎么实现分布式锁?
190.redis 分布式锁有什么缺陷?
191.redis 如何做内存优化?
192.redis 淘汰策略有哪些?
193.redis 常见的性能问题有哪些?该如何解决?
JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

堆是全局的,静态和全局变量,new 得到的变量,都放在堆中;
栈是在每个方法进入的时候分配一小块,由系统自动分配,存储局部变量、方法参数等
队列:先进先出
栈:后进先出
JDK主要有3个自带ClassLoader:
最基础:Bootstrap ClassLoader(加载JDK的/lib目录下的类)次基础:Extension ClassLoader(加载JDK的/lib/ext目录下的类)普通:Application ClassLoader(程序自己classpath下的类)双亲委派模型要求如果一个类可以被委派最基础的ClassLoader加载,就不能让高层的ClassLoader加载。这样你就知道你用的String类一定是被BootstrapClasserLoader加载的/lib下的那个rt.jar的那个java/lang/String.class.
首先双亲委派原则本身并非 JVM 强制模型。
SPI 的调用方和接口定义方很可能都在 Java 的核心类库之中,而实现类交由开发者实现,然而实现类并不会被启动类加载器所加载,基于双亲委派的可见性原则,SPI 调用方无法拿到实现类。SPI Serviceloader 通过线程上下文获取能够加载实现类的classloader,一般情况下是 application classloader,绕过了这层限制,逻辑上打破了双亲委派原则。
类加载过程即是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程。
哪些对象可以作为GC Roots?
虚拟机栈中引用的对象方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中JNI(native方法,调用C++代码)引用的对象Java中有四种引用类型,引用强度由强到弱:强引用、软引用、弱引用、虚引用。针对不同的引用类型,GC的回收策略不同。
强引用复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半。
优点:简单高效,不会出现内存碎片
缺点:内存利用率低,存活对象较多时需要复制的次数多,效率明显降低
标记-清除算法
首先标记所有需要回收的对象,然后统一回收被标记的对象
优点:利用率100%
缺点:1、标记和清除效率都不高(对比复制算法)2、会产生大量不连续的内存碎片
标记-整理算法
首先标记出所有需要回收的对象,在标记完成后,后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端,边界以外的内存。
优点:内存利用率100%,没有内存碎片
缺点:标记和清除效率都不高(对比复制算法及标记-清除算法)
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
Serial
新生代单线程收集器,优点是简单高效,Client模式下默认的新生代收集器
ParNew
新生代并行收集器,Serial收集器的多线程版本
Parallel Scavenge
新生代并行收集器,追求高吞吐量,高效利用 CPU。
Serial Old
Serial收集器的老年代版本
Parallel Old
Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
CMS
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
基于标记-清除算法实现,过程分为4步:
(1)初始标记
仅仅是标记 GC Roots 内直接关联的对象,这个阶段速度很快
(2)并发标记
进行的是 GC Tracing,从 GC Roots 开始对堆进行可达性分析,找出存活对象。
(3)重新标记
为了 修正 并发期间由于 用户进行运作 导致的 标记变动 的那一部分对象的 标记记录。这个阶段的 停顿时间 一般会比 初始标记阶段 稍长一些,但远比 并发标记 的时间短
(4)并发清除
并发清除 阶段会清除垃圾对象。
优点:并发收集、低停顿
缺点:1)CMS回收器对CPU资源非常依赖 2)CMS回收器无法清除浮动垃圾 3)垃圾收集结束后残余大量空间碎片,需要配合内存整理策略优化
G1
标记-整理垃圾收集器,JDK1.7后全新的收集器,取代CMS。
G1收集器的特点:
(1)并行与并发
使用多个 CPU 来缩短 Stop-the-World 的 停顿时间,部分其他回收器需要停顿 Java 线程执行的 GC 动作,G1 回收器仍然可以通过 并发的方式 让 Java 程序继续执行。
(2)分代回收
与其他回收器一样,分代概念 在 G1 中依然得以保留。虽然 G1 可以不需要 其他回收器配合 就能独立管理 整个GC堆,但它能够采用 不同的策略 去处理 新创建的对象 和 已经存活 一段时间、熬过多次 GC 的旧对象,以获取更好的回收效果。新生代 和 老年代 不再是 物理隔离,是多个 大小相等 的独立 Region。
(3)空间整合
与 CMS 的 标记—清理 算法不同,G1 从 整体 来看是基于 标记—整理 算法实现的回收器。从 局部(两个 Region 之间)上来看是基于 复制算法 实现的。
但无论如何,这 两种算法 都意味着 G1 运作期间 不会产生内存空间碎片,回收后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象 时不会因为无法找到 连续内存空间 而提前触发 下一次 GC。
(4)可预测的停顿
这是 G1 相对于 CMS 的另一大优势,降低停顿时间 是 G1 和 CMS 共同的关注点。G1 除了追求 低停顿 外,还能建立 可预测 的 停顿时间模型,能让使用者明确指定在一个 长度 为 M 毫秒的 时间片段 内,消耗在 垃圾回收 上的时间不得超过 N 毫秒。(后台维护的 优先列表,优先回收 价值大 的 Region)。
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
(1)把 Eden + From Survivor 存活的对象放入 To Survivor 区;
(2)清空 Eden 和 From Survivor 分区;
(3)From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。
皓盘云建最新版下载v9.0 安卓版
53.38MB |商务办公
ris云客移动销售系统最新版下载v1.1.25 安卓手机版
42.71M |商务办公
粤语翻译帮app下载v1.1.1 安卓版
60.01MB |生活服务
人生笔记app官方版下载v1.19.4 安卓版
125.88MB |系统工具
萝卜笔记app下载v1.1.6 安卓版
46.29MB |生活服务
贯联商户端app下载v6.1.8 安卓版
12.54MB |商务办公
jotmo笔记app下载v2.30.0 安卓版
50.06MB |系统工具
鑫钜出行共享汽车app下载v1.5.2
44.7M |生活服务