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

发表评论

邮箱地址不会被公开。 必填项已用*标注