显示锁和内置锁
Synchronized属于内置锁。Lock接口属于显示锁。
Lock
Lock类是一个接口,核心方法有lock(),unLock(),tryLock()
synchronized和lock比较
synchronized会比lock消耗的性能会少一点。因为lock是一个类,使用时需要创建一个对象的实例。而lock又比synchronized使用起来更灵活。
Lock的两个实现类
Lock接口有两个实现用到的比较多:ReentrantLock(可重入锁,默认是非公平锁)和ReentrantReadWriteLock(读写锁)
Lock使用范式
try{
lock.Lock();
//做业务逻辑
} finally{
//解锁
lock.unlock();
}
可重入锁
不能锁自己,比如递归调用时,可以继续进入这把锁。
所谓锁的公平和非公平
公平就是竞争锁的线程排队等候获取锁,等待时间最长的线程先拿锁,后来的排队等候。非公平就是谁先抢到就是谁的(因为线程从等待到唤醒需要上下文切换的时间,而这时正好有新的线程来拿锁,可能新来的线程先拿到)。Syn是非公平锁。
公平锁和非公平锁其实不是由aqs来管的,是由实现这个锁来管的。非公平锁就是先尝试抢一次,如果抢到了则获取锁。公平锁是判断当前队列有没有节点等待,如果有的话则放到队列尾部等待。
读写锁
创建读写锁:ReentrantReadWriteLock是实现类,ReadWriteLock是接口,如果要创建的话应该是ReadWriteLock lock = new ReentrantReadWriteLock();
读写锁的机制:写独占,读共享,但是读写互斥。
ReentrantReadWriteLock:ReentrantReadWriteLock实现上,读和写用的是一把锁,通过sync里的status值来记录的,因为status是int型,32位,高(16-32)16位用来记录读锁,低(0-16)16位用来记录写锁,而可重入的读锁通过ThreadLocal来实现记录重入次数。
Condition接口
类似于syn中用到的notify和wait方法。配合Lock使用。Signal()方法对应notify,await()方法对应wait方法。唤醒基本用signal,而不用signalAll。
LockSupport
LockSupport定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,park方法是阻塞线程,unPark(Thread thread)是唤醒线程。而LockSupport 也成为构建同步组件的基础工具。
CLH
队列锁。每一个锁都有两个参数,myPred和locked,locked等于当前线程使用锁的情况,myPred是一个自旋规则,会不断的向前面的线程查看locked值,当前面线程使用完锁后,会把自己的locked置为false,本线线程就能使用该锁了,当使用完再把自己的locked置为fasle,供后面的线程使用。
AQS(AbstractQueuedSynchronizer同步器)
同步器的设计基于模板方法模式。,定义一个操作中的算法的骨架,而将一些步骤的实现延迟到子类中。模板方法模式最常见的使用就是spring框架中的各种template。