Java基础篇
抽象类和接口的异同
不同:
抽象类:
1.抽象类中可以定义构造器
2.可以有抽象方法和具体方法
3.接口中的成员全都是 public 的
4.抽象类中可以定义成员变量
5.有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法
6.抽象类中可以包含静态方法
7.一个类只能继承一个抽象类
接口:
1.接口中不能定义构造器
2.方法全部都是抽象方法
3.抽象类中的成员可以是 private、默认、 protected、 public
4.接口中定义的成员变量实际上都是常量
5.接口中不能有静态方法
6.一个类可以实现多个接口
事物的传播机制
REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。
SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。
MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
REQUIRES_NEW:创建一个新事务,如果当前事务不存在,把当前事务挂起。
NOT_SUPPORTED:无事务执行,如果当前事务不存在,把当前事务挂起。
NEVER:无事务执行,如果当前有事务则抛出Exception。
NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
相同:
1.不能够实例化
2.可以将抽象类和接口类型作为引用类型
3.一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要
被声明为抽象类
Java四种线程池
newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
- newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程
- newFixedThreadPool: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
- newScheduledThreadPool :创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
Java线程同步的7种方法
- synchronized修饰的同步方法
- synchronized修饰的同步代码块
- volatile实现线程同步
- ReentrantLock
- ThreadLocal
- 阻塞队列LinkedBlockingQueue
- 原子变量 Atomic包
synchronized和lock的区别
- lock是接口,synchronized是内置语言实现的关键字
- synchronized发生异常会自动释放占有的锁,而lock必须手动unlock
- lock在等待锁的过程中可以用interrupt来终止等待,synchronized只能等待锁释放
- lock可以提高多个线程进行读操作的效率,比如readWriteLock实现了读写分离
synchronized(this)和synchronized(class)的区别
- synchronized(this) 锁住的是对象,当两个线程使用同一个A的实例a里的同步方法时【如线程1调用a.method1 (),线程2调用a.method2()或者调用a.method1()】,会出现同步的现象,即两个线程里的这两个方法不能同时执行; 如果这两个线程分别new了不同的A的实例,然后用不同的实例分别调用method1 ()和method2(),不会出现同步的问题。
- synchronized(class) 锁住的是class,即使不同的线程创建了A类的不同实例,分别调用同步方法,也会存在同步现象,当然用同一个实例调用同步方法,更会出现同步现象
concurrentHashmap
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。
jdk动态代理和cglib代理的区别
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;
JVM篇
Java 类加载过程?
Java 类加载需要经历一下 5 个过程:
- 加载
加载是类加载的第一个过程,在这个阶段,将完成一下三件事情:
通过一个类的全限定名获取该类的二进制流。
将该二进制流中的静态存储结构转化为方法去运行时数据结构。
在内存中生成该类的 Class 对象,作为该类的数据访问入口。 - 验证
验证的目的是为了确保 Class 文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:
文件格式验证:验证字节流是否符合 Class 文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.
元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。
字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。 - 准备
准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。
public static int value=123;//在准备阶段value初始值为0 。在初始化阶段才会变为123 。 - 解析
该阶段主要完成符号引用到直接引用的转换动作。将常量池内的符号引用替换为直接引用。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。 - 初始化
初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的 Java 程序代码。执行类构造器<clinit>()
方法
Java内存分配
- 程序计数器(线程私有):当前吸纳城所执行的字节码行号指示器
- 虚拟机栈(栈)(线程私有):Java方法执行的内存模型,每个方法在执行的同时,会创建局部变量表(基本数据类型、对象引用和returnAddress类型)
- 本地方法栈(线程私有):为虚拟机使用的Native方法服务(HotSpot虚拟机将本地方法栈和虚拟机栈合二为一)
- 堆(线程共享):又叫GC堆,是垃圾回收的主要区域,存放对象实例
- 方法区(线程共享):又叫永久代,存储已被虚拟机加载的类信息、常量、静态变量
对象的创建
对JVM来说,一个新的对象产生了,但从Java程序视角来说,对象的创建刚刚开始,执行new后悔执行<init>
方法
GC
对象是否已死
- 引用计数法:
对象被引用时,计数器值加1,失效减1
无法解决对象间的相互引用
2.可达性分析:
以GC Roots 的对象为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链则此对象不可用
GC算法
- 标记-清除:先标记所有需要回收的对象,后回收这些对象
缺点:1.效率低 2.空间碎片太多 - 复制(用于新生代的回收):内存分为两块,当一块用完了将存活对象复制到另一半上
- 标记-整理(用于年老代的收集):标记需要清除的对象,将存活对象向一端移动,清理掉端边界以外的对象
- 分代收集:现代垃圾收集
内存分配与回收策略
对象主要分配在Eden区,当Eden区满,虚拟机发生MinorGC,将存货对象复制进Survior区
大对象直接进入年老代
长期存活对象进入年老大代
类加载器
从JVM来说分为
- 启动类加载器(BootStrap ClassLoader):虚拟机的一部分,C++实现
- 其他类加载器(Java实现):独立于虚拟机,继承java.lang.ClassLoader
从Java开发来说分为
- 启动类加载器(BootStrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 应用程序类加载器(Application ClassLoader)
双亲委派机制
双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父加载器反馈自己无法完成这个加载请求,子加载器才会尝试自己去加载
优点:Java类随着类加载器一起具备了一种带有优先级的层次关系
Java内存模型
JVM调优
https://blog.csdn.net/sun1021873926/article/details/78002118
CAS 实现自旋锁
既然用锁或 synchronized 关键字可以实现原子操作,那么为什么还要用 CAS 呢,因为加锁或使用 synchronized 关键字带来的性能损耗较大,而用 CAS 可以实现乐观锁,它实际上是直接利用了 CPU 层面的指令,所以性能很高。
CAS 是实现自旋锁的基础,CAS 利用 CPU 指令保证了操作的原子性,以达到锁的效果,至于自旋呢,看字面意思也很明白,自己旋转,翻译成人话就是循环,一般是用一个无限循环实现。这样一来,一个无限循环中,执行一个 CAS 操作,当操作成功,返回 true 时,循环结束;当返回 false 时,接着执行循环,继续尝试 CAS 操作,直到返回 true。
数据库篇
mysql组合索引生效原则
例如索引(a,b,c)
组合索引的生效原则是 从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用;
比如
where a=3 and b=45 and c=5 … 这种三个索引顺序使用中间没有断点,全部发挥作用;
where a=3 and c=5… 这种情况下b就是断点,a发挥了效果,c没有效果
where b=3 and c=4… 这种情况下a就是断点,在a后面的索引都没有发挥作用,这种写法联合索引没有发挥任何效果;
where b=45 and a=3 and c=5 … 这个跟第一个一样,全部发挥作用,abc只要用上了就行,跟写的顺序无关
Mysql事物隔离级别
事务的并发问题
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。也就是说,当前事务读第一次取到的数据比后来读取到数据条目少。
不可重复读和幻读两者有些相似,但是前者针对的是update或delete,后者针对的insert。
在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
mysql默认的事务隔离级别为 可重复读(repeatable-read)
sql行列转换
要查询成
sql语句
select employee,
MAX(case weekname WHEN '星期一' then income ELSE 0 END ) '星期一',
MAX(case weekname WHEN '星期二' then income ELSE 0 END ) '星期二',
MAX(case weekname WHEN '星期三' then income ELSE 0 END ) '星期三',
MAX(case weekname WHEN '星期四' then income ELSE 0 END ) '星期四',
MAX(case weekname WHEN '星期五' then income ELSE 0 END ) '星期五',
MAX(case weekname WHEN '星期六' then income ELSE 0 END ) '星期六',
MAX(case weekname WHEN '星期日' then income ELSE 0 END ) '星期日'
from week_income
GROUP BY employee
TCP和UDP的区别:
1)TCP提供面向连接的传输,通信前要先建立连接(三次握手机制);UDP提供无连接的传输,通信前不需要建立连接。
2)TCP提供可靠的传输(有序,无差错,不丢失,不重复);UDP提供不可靠的传输。
3)TCP面向字节流的传输,因此它能将信息分割成组,并在接收端将其重组;UDP是面向数据报的传输,没有分组开销。
4)TCP提供拥塞控制和流量控制机制;UDP不提供拥塞控制和流量控制机制。
分布式
https://www.cnblogs.com/lingqin/p/10041672.html
计算机网络篇
TCP三次握手和四次挥手
https://www.cnblogs.com/leezhxing/p/4524176.html