synchronized 和 ReentrantLock的区别
synchronized 和 ReentrantLock 都是 Java 中提供的可重入锁,二者的主要区别有以下 5 个:
- 用法不同:synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块。ReentrantLock 在使用之前需要先创建 ReentrantLock 对象,然后使用 lock 方法进行加锁,使用完之后再调用 unlock 方法释放锁
- 获取锁和释放锁的机制不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。
- 锁类型不同:synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁。
- 响应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。
- 底层实现不同:synchronized 是 JVM 层面通过监视器实现的,而 ReentrantLock 是基于 AQS 实现的。
ConcurrentHashMap的底层实现
为什么ConcurrentHashMap是线程安全的?
ConcurrentHashMap是线程安全的数组,是HashTable的替代品,同为线程安全,其性能要比HashTable更好 。
1、在 JDK 1.7 中它使用的是数组加链表的形式实现的,而数组又分为:大数组 Segment 和小数组 HashEntry。大数组 Segment 可以理解为 MySQL 中的数据库,而每个数据库(Segment)中又有很多张表 HashEntry,每个 HashEntry 中又有多条数据,这些数据是用链表连接的。
- Segment 本身是基于 ReentrantLock 实现的加锁和释放锁的操作,这样就能保证多个线程同时访问 ConcurrentHashMap 时,同一时间只有一个线程能操作相应的节点,这样就保证了 ConcurrentHashMap 的线程安全了。
2、在JDK 1.8 中 ConcurrentHashMap 使用的是数组+链表/红黑树的方式实现的,
- 它是通过 CAS 或 synchronized 来实现线程安全的,并且它的锁粒度更小,查询性能也更高。
多态的实现原理 和 实现方法
多态的实现原理主要是依靠“动态绑定”和“虚拟方法调用”,它的实现流程如下:
- 动态绑定(Dynamic Binding):指的是在编译时,Java 编译器只能知道变量的声明类型,而无法确定其实际的对象类型。而在运行时,Java 虚拟机(JVM)会通过动态绑定来解析实际对象的类型。这意味着,编译器会推迟方法的绑定(即方法的具体调用)到运行时。正是这种动态绑定机制,使得多态成为可能。
- 虚拟方法调用是在运行时根据实际对象的类型来确定要调用的方法的机制。当通过父类类型的引用变量调用被子类重写的方法时,虚拟机会根据实际对象的类型来确定要调用的方法版本,而不是根据引用变量的声明类型。
通过方法重写和方法重载来实现
${} 和 #{} 有什么区别?
- ${} 和 #{} 都是 MyBatis 中用来替换参数的,它们都可以将用户传递过来的参数,替换到 MyBatis 最终生成的 SQL 中。
- 它们二者的区别主要体现在:
- 1、功能不同:
${}
是直接替换,而 #{} 是预处理;- 2、使用场景不同:普通参数使用 #{},如果传递的是 SQL 命令或 SQL 关键字,需要使用
${}
,但在使用前一定要做好安全验证;- 3、安全性不同:使用
${}
存在安全问题,而 #{} 则不存在安全问题。
<select id="getUserById" resultType="com.example.demo.model.UserInfo">select * from userinfo where id=${id}
</select>
<select id="getUserById" resultType="com.example.demo.model.UserInfo">select * from userinfo where id=#{id}
</select>