显式锁
Java 程序是靠synchronized 关键字实现锁功能的,使用synchronized 关键字将会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放。
Lock
在finally 块中释放锁,目的是保证在获取到锁之后,最终能够被释放。
尝试拿锁等待原理: LockSupport的park()和 unpark()
park()和unpark()提供了类似wait()和notify()的机制,但是并不用获得对象的监视器,而是获得许可,park()就是堵塞,挂起,不许可的意思。unpark()就是发放许可。
ReentrantLock
1. 锁的可重入
简单地讲就是:“同一个线程对于已经获得到的锁,可以多次继续申请到该锁的使用权”。而synchronized 关键字隐式的支持重进入,比如一个synchronized修饰的递归方法,在方法执行时,执行线程在获取了锁之后仍能连续多次地获得该锁。ReentrantLock 在调用lock()方法时,已经获取到锁的线程,能够再次调用lock()方法获取锁而不被阻塞。
2. 公平和非公平锁
先对锁进行获取的请求一定先被满足,那么这个锁是公平的,反之,是不公平的。
在激烈竞争的情况下,非公平锁的性能高于公平锁的性能的一个原因是:在恢复一个被挂起的线程与该线程真正开始运行之间存在着严重的延迟。
读写锁ReentrantReadWriteLock
之前提到锁(如Mutex 和ReentrantLock)基本都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。
一般情况下,读写锁的性能都会比排它锁好,因为大多数场景读是多于写的。在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。
Condition 接口
任意一个Java 对象,都拥有一组监视器方法(定义在java.lang.Object 上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与synchronized 同步关键字配合,可以实现等待/通知模式。Condition 接口也提供了类似Object 的监视器方法,与Lock 配合可以实现等待/通知模式。