1、什么时候会触发类的初始化
关于在什么情况下需要开始类加载过程的第一个阶段“加载”,《Java虚拟机规范》中并没有进行强制约束,这带你可以交给虚拟机的具体实现来自由把我。但是对于初始化阶段,《Java虚拟机规范》则是严格规定了有且只有六种情况必须立即对类进行“初始化”(而加载、验证、准备阶段自然需要在此之前开始):
- 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要触发其初始化阶段,能生成这四条指令的典型场景有:
- 使用new关键字实例化对象的时候
- 读取或设置一个类型的静态字段的时候(被final修饰、已在编译器把结果放入常量池的静态字段除外)
- 调用一个类型的静态方法的时候
- 使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化
- 当初始化类的时候,如果发现其父类还没有被进行过初始化,则需要先触发其父类的初始化
- 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类
- 当使用JDK7新加入的动态语言支持时,如果一个
java.lang.invoke.MethodHandle
实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化 - 当一个接口中定义了JDK8新加入的默认方法时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化
2、Synchronized和ReentrantLock的区别?
先从这两个的原始构成来说
synchronized属于JVM层面,属于java的关键字。而Lock是具体类是api层面的
再从使用方法的维度进行回答
synchronized不需要用户去手动释放锁,当synchronized代码执行后,系统会自动让线程释放对锁的占用。ReentrantLock则需要用户去手动释放锁,若没有主动释放锁,就有可能出现死锁的现象,需要lock() 和 unlock() 配置try catch语句来完成
再从是否可重复的角度回答
synchronized和ReentrantLock都是可重入的。
再从是等待是否可中断来回答
synchronized不可中断,除非抛出异常或者正常运行完成。ReentrantLock可中断,可以设置超时方法,它通过lockInterruptibly()和interrupt() 实现中断效果,使用trylock(long timeout, TimeUnit unit)设置超时
再从加锁是否公平进行比较
synchronized是非公平锁。ReentrantLock是默认非公平锁,构造函数可以传递boolean值,true为公平锁,false为非公平锁
从条件变量的区别来进行回答
synchronized的entrySet只有一个,所以要么随机唤醒,要么全部唤醒。ReentrantLock则可以用来实现分组唤醒需要唤醒的线程,可以精确唤醒,而不是像synchronized那样,要么随机,要么全部唤醒
3、MySQL事务ACID是什么意思?
- 原子性(atomicity):
原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
即要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出现数据不一致的情形,A账户减去100元,而B账户增加100元操作失败,系统将无故丢失100元。
- 一致性(consistency):
(国内很多网站上对一致性的阐述有误,具体你可以参考 Wikipedia 对Consistency的阐述)
根据定义,一致性是指事务执行前后,数据从一个 合法性状态
变换到另外一个 合法性状态
。这种状态是 语义上
的而不是语法上的,跟具体的业务有关。
那什么是合法的数据状态呢?满足 预定的约束
的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。
举例1:
A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现了此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须>=0。
举例2:
A账户200元,转账50给B账户,A账户的钱扣了,但是B账户因为各种意外,余额没有增加。你也知道此时数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的总余额必须不变。
举例3:
在数据表中我们将性名
字段设置为唯一性约束
,这时当一个事务进行提交或者事务发生回滚的时候,如果数据表中的姓名不唯一,就破坏了事务的一致性要求。
- 隔离性(isolation):
事务的隔离性是指一个事务的执行不能被其他事务干扰
,即一个事务内部的操作及使用的数据对并发
的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
如果无法保证隔离性会怎么样?假设A账户有200元,B账户0元。A账户往B账户转账两次,每次金额为50元,分别在两个事务中执行。如果无法保证隔离性,会出现下面的情形:
UPDATE accounts SET money = money - 50 WHERE NAME = 'AA';
UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';
- 持久性(durability):
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的
,接下来的其他操作和数据库故障不应该对其有任何影响。
持久性是通过 事务日志
来保证的。日志包括了 重做日志
和 回滚日志
。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。
总结
ACID是事务的四大特征,在这四个特性中,原子性是基础,隔离性是手段,一致性是约束条件,而持久性是我们的目的。
数据库事务,其实就是数据库设计者为了方便起见,把需要保证
原子性
、隔离性
、一致性
和持久性
的一个或多个数据库操作称为一个事务
4、Zset的底层实现是什么?
zset由压缩列表和跳表实现
当有序集合对象同时满足以下两个条件时,对象使用 ziplist 编码:
1、保存的元素数量小于128;
2、保存的所有元素长度都小于64字节。
不能满足上面两个条件的使用 skiplist 编码。
具体跳表和压缩列表的实现见博客
- [https://www.cnblogs.com/ysocean/p/9080942.html#_label7](
5、TCP依靠哪些机制来保证可靠传输?
-
校验和:
TCP
通过校验和检测数据在传输过程中是否发生改变,如果收到的报文段的校验和有差错,报文段将被丢弃。 -
序列号和确认应答:
TCP
给发送的每一个报文段中都有序号字段,每次接收方收到数据后,都会对传输方进行确认应答,即发送确认报文段(ACK)
,其中的确认号告诉发送方成功接收了哪些数据以及下一次请求的数据从哪里开始发。除此之外,接收方可以根据序列号对数据包进行排序,把有序数据传送给应用层,并丢弃重复的数据。 -
超时重传:当
TCP
发出一个报文段后,它将启动一个定时器,等待接收端发回的确认。如果超过定时器超时还没有收到确认,发送方将重发这个报文段。 -
约定最大报文段长度(MSS):在建立
TCP
连接的时候,双方可以在头部选项字段中约定最大报文段长度作为发送的单位,理想的情况下是该长度的数据刚好不被网络层分片。 -
流量控制:
TCP
通过滑动窗口机制实现流量控制,窗口(缓冲区)的大小就是发送方在无需等待确认报文段
的情况下还能发送的最大数据量。TCP
通过窗口大小来协调端对端的发送速度,确保接收端来得及接收,从而尽可能减少丢包。 -
拥塞控制:通过拥塞控制算法(慢开始、拥塞避免、快重传、快恢复),根据全局网络的拥塞程度来调整拥塞窗口的大小,改善网络拥塞程度,从而尽可能减少丢包。
备注:发送窗口的大小等于Min(接收窗口, 拥塞窗口),因此是两种流量控制和拥塞控制的共同作用。