Java 8 的角度看Lock和Synchronized的机制

1、对IBM Developer Blog的总结:

Synchronized简介:

把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 (1)原子性(atomicity)和 (2)可见性(visibility)。原子性意味着一个线程一次只能执行由一个指定监控对象(lock)保护的代码,可见性则更为微妙;它要对付内存缓存和编译器优化的各种反常行为。

一般来说,线程以某种不必让其他线程立即可以看到的方式(不管这些线程在寄存器中、在处理器特定的缓存中,还是通过指令重排或者其他编译器优化),不受缓存变量值的约束,但是如果开发人员使用了同步,那么运行库将确保某一线程对变量所做的更新在程序进入由同一监控器(lock)保护的另一个 synchronized 块时,将立刻看到这些更新。类似的规则也存在于volatile 变量上。

Synchronized缺漏:

它有一些功能性的限制 —— 它无法中断一个正在等候获得锁的线程,也无法通过轮询得到锁,如果不想等下去,也就没法得到锁。同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈帧中进行

ReentranckLock类简介:

把锁定的实现作为 Java 类,而不是语言的特性来实现。使它可以实现不同的调度算法、性能特性或者锁定语义。

ReentrantLock 类实现了 Lock ,它拥有与synchronized 相同的并发性和内存语义,但是添加了类似轮询锁、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)

ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的。

Synchronized VS ReentranckLock类:

  Lock  和 synchronized 有一点明显的区别 —— lock 必须在 finally 块中释放

Lock可以实现公平锁或不公平锁,而Synchronized是不公平的,而且永远都是不公平的。但 JVM 保证了所有线程最终都会得到它们所等候的锁,但是Lock作为默认设置,把公平设置为 false ,除非公平对您的算法至关重要,需要严格按照线程排队的顺序对其进行服务

Lock性能和伸缩性都比较好(在JDK5.0),但是大多数情况Synchronized就足够了,而且更容易理解

ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”。也就是说ReentrantLock在同一个时间点只能被一个线程获取。Java的synchronized块并不保证尝试进入它们的线程的顺序。因此,如果多个线程不断竞争访问相同的synchronized同步块,就存在一种风险,其中一个或多个线程永远也得不到访问权 —— 也就是说访问权总是分配给了其它线程。这种情况被称作线程饥饿。为了避免这种问题,锁需要实现公平性。


2、对51CTO上的Blog总结:

1、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定;

2、ReentrantLock、ReentrantReadWriteLock,、StampedLock都是对象层面的锁定,要保证锁定一定会被释放,就必须将unLock()放到finally{}中;

3、StampedLock 对吞吐量有巨大的改进,特别是在读线程越来越多的场景下;

4、StampedLock有一个复杂的API,对于加锁操作,很容易误用其他方法;

5、当只有少量竞争者的时候,synchronized是一个很好的通用的锁实现;

6、当线程增长能够预估,ReentrantLock是一个很好的通用的锁实现;

StampedLock 可以说是Lock的一个很好的补充,吞吐量以及性能上的提升足以打动很多人了,但并不是说要替代之前Lock的东西,毕竟他还是有些应用场景的,起码API比StampedLock容易入手


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值