锁
在java多线程中,我们知道使用synchronized关键字来实现线程间的同步互斥操作,那么其实还有一个更优秀的机制去完成“同步互斥”工作,它就是Lock对象,即重入锁和读写锁。他们具有比synchronized更为强大的功能,并且具有嗅探锁定、多路分支等功能。
ReentrantLock(重入锁)
- 概念:
在需要进行同步的代码部分加上锁定,但最后一定要释放锁,不然会造成锁用于无法释放,其他线程永远进不来的结果。
1 | public class UseReentrantLock { |
锁与等待/通知
我们在使用synchronized的时候,如果需要多线程间进行协作工作则需要Object的wait()和notify()、notifyAll方法配合使用。同样,我们在使用Lock的时候,可以使用一个新的等待/通知的类Condition,这个Condition一定是针对具体的某一把锁,也就是在只有锁的基础之上才会产生Condition。
1 | public class UseCondition { |
多个Condition
可以通过一个Lock对象产生多个Condition进行线程间的交互,非常的灵活。可以使得部分需要唤醒的线程唤醒,其他的线程则继续等待通知。
1 | public class UseManyCondition { |
Lock/Condition其他用法
公平锁和非公平锁:ReentrantLock lock = new ReentrantLock(boolean isFair),lock用法:
- lock.tryLock():
尝试获得锁,获得结果用true/false返回。 - lock.tryLock(paramLong, paramTimeUnit):
在给定的时间内尝试获得锁,获得结果用true/false返回。 - lock.isFair():
是否公平锁。 - lock.isLocked():
是否锁定。 - lock.getHoldCount():
查询当前线程保持此锁的个数,也就是调用lock()次数。 - lock.lockInterruptibly():
优先响应中断的锁。 - lock.getQueueLength():
返回正在等待获取此锁的线程数。 - lock.getWaitQueueLength(Condition paramCondition):
返回等待与锁定相关的给定条件Condition的线程数。 - lock.hasQueuedThread(Thread paramThread):
查询指定的线程是否正在等待此锁。 - lock.hasQueuedThreads():
查询是否有线程正在等待此锁。 - lock.hasWaiters(Condition paramCondition):
查询是否有线程正在等待与此锁定有关的condition条件。
ReentrantReadWriteLock(读写锁)
读写锁,其核心就是实现读写分离。在高并发访问下,尤其是读多写少的情况下,性能要员高于重入锁。对于synchronized、ReentrantLock,我们知道,同一时间内,只能有一个线程进行访问被锁定的代码。读写锁则不同,其本质是分成两个锁,即读锁和写锁。在读锁下,多个线程可以并发的进行访问,但是在写锁的时候,只能一个一个顺序访问,即读读共享,写写互斥,读写互斥。
1 | public class UseReentrantReadWriteLock { |
锁优化
- 避免死锁。
- 减小锁持有时间。
- 减小锁的粒度。
- 锁的分离。
- 尽量使用无锁的操作,如原子操作(Atomic系列类),volatile关键字。