Synchronized 和 ReentranLock的区别在于上面
Synchronized是Java内建的同步机制,是原生的互斥机制
ReentranLock是后来提供的锁实现,语义类似,可以直接调用lock()方法获取,支持公平性和自定义条件,但在释放的时候需要显式的进行调用unlock进行释放
在后续的改进版本中,在低竞争场景中,synchronized可能由于ReentranLock
接下来我们需要理解的是
线程安全是一个多线程环境下的概念,就是保证多线程情况下对共享的可修改的状态的正确性保证
状态不是共享,或者说是不可修改的,就不存在线程安全
所以线程安全的本质保证就是封装和不可变性
或者说
保证 原子性 有序性 可见性
对于一段简单的代码,假如如下
如果使用javap反编译,可以看到如下的语义
使用monitorenter/monitorexit进行同步包裹
而ReentranLock,是一个同步锁,是一个线程试图获取到已经获取的锁的时候,锁会自动的获取成功,这就是锁的获取线程为单位而不是基于调用次数,Java锁强调的是再入性
而且可以设置公平锁,就是根据等待时间而进行分配线程的情况,
对于Synchronized,则无法选择公平性的选择,永远都是不公平的,主流操作系统线程调度的选择也是不公平的
但对于实际场景,对于线程的公平获取保证不是很重要,保证公平性还可能导致额外的开销,所以并不建议指定为公平锁
现在try-catch-finally的手动释放ReentranLock已经改为了try-with-resource 可以自动的释放锁
而且ReentranLock可以进行带有超时的获取锁尝试
可以判断是否有线程在等待锁
进行中断等待
而且还支持多个不同的条件的获取,简称为变量 Condition.
比如标准类库中ArrayBlockQueue的源码
两个条件是在同一个再入锁中创建出来,下面的take方法,判断是否条件满足
队列为空的时候,take的线程正确行为等待入队后出队,而不是直接返回
等待入队的时候,就如下的唤醒
通过signal和await的组合,完成了条件判断和通知等待线程,完成了线程转换
这样,我们初步介绍了下什么是线程安全,对比了Synchronized和ReetrantLock