开头给自己得渣渣发音备注下: synchronized读法: ['sɪŋkrənaɪzd]
ReentrantLock和synchronized都是加锁式同步,当一个线程获取了对象锁后,其它要进入同步块的线程就必须阻塞在同步块外等待。线程的阻塞和唤醒需要操作系统在用户态和内核态之间切换,所以,ReentrantLock和synchronized都是代价比较高的。
- 关于用户态和内核态得解释,摘自百度百科如下:
内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。
用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。
- 为什么要有用户态和内核态?
由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 -- 用户态和内核态。
- 实现方式
synchronized的锁机制是JVM实现的,是原生语法层面的;synchronized是Java的关键字.
ReentrantLock是API层面的锁,需在代码里面调用api逻辑来实现.
所以synchronized在使用上更简单方便一些,但是从灵活层面来说,ReentranLock更加灵活,可以根据api来灵活使用,可控性更强,可以实现更细粒度.
ps: 在使用ReentrantLock时,一定要注意lock和unlock的匹配和顺序,否则就可能造成死锁。常见的方案是把unlock放在异常处理的finally语句块中。
- 性能
synchronized性能在jdk1.5之前较差,jdk1.6之后逐步优化,锁机制的升级,引入轻量级锁,偏向锁.官方更推荐使用synchronized,因为二者现在性能差不多,且synchronized使用起来更简单方便,避免使用ReentrantLock过程中,可能使用不当造成死锁.
- 公平锁
公平锁指的是,是否根据排队的顺序获取到锁,如A线程目前获取到锁,后面排队还有BCDEF五个线程,A执行完,把锁给B,B执行完给C持续下去;如果是非公平锁,在A执行完,把锁一扔,BCDEF五个线程抢锁,谁抢到轮到谁.
synchronized是非公平锁,ReentrantLock默认也是非公平锁,但是ReentrantLock可以实现公平锁.通过new ReentrantLock(true)可以用来构造一个公平锁.
- 是否可重入锁
可重入锁指的是一个线程可以对某个资源重复加锁,最常见的就是递归,如线程A调用了方法B,B是加锁的,A线程获取了B的锁,如果B中递归调用了B自己,需要再次获取B的锁,持续下次,直到退出.synchronized和ReentrantLock都是可重入锁.
- ReentrantLock更灵活
1.ReentrantLock更灵活主要提现在实现方式是API,可以根据API逻辑来自由实现;
2.ReentrantLock可以通过lockInterruptibly()方法来打断等待的线程,转去执行其他的线程.
3.另外有时我们不希望在一个锁结束后,唤醒全部的线程,而是唤醒部分线程,这种方式在synchronized下是无法实现的。但是,ReentrantLock通过提供一个Contition类,可以同时绑定多个对象,来实现线程的分组唤醒。
4.提供公平锁机制的实现.