可重入的意思是线程可以同时多次请求同一把锁,而不会导致自己死锁。
1.相似点:
都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待。
2.不同点
锁的实现:
Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的。
性能的区别:
在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞
功能区别:
便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁
ReenTrantLock独有的能力:
ReenTrantLock可以指定是公平锁还是非公平锁。默认非公平锁。
映射在在代码上,在重入锁代码里有两个staric final类,NonfairSync和failSync,而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
ReenTrantLock提供了一种能够中断等待锁的线程的机制,调用的是lockInterruptibly(),
重入锁可以规定一定的时间,调用的是tryLock方法,如果一个线程迟迟拿不到锁,规定时间过后就让线程自动放弃。
synchronized是怎么实现的呢?
他会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。