本文最后更新于46 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
锁主要是用来控制多个现成访问共享变量的方式,在Lock接口出现之前,Java主要是靠Synchronized关键字来实现锁功能,在Lock接口出现后,他能实现Synchronized关键字类似的同步功能。
Lock的使用:
Lock lock = new ReetrantLock();
lock.lock();
try{
} finally {
lock.unlock();
}
- 解锁过程放入finally块能确保锁能被释放
- 加锁过程不要写在try里,因为加锁如果发生异常,也会进入finally块导致锁无故释放
- 此外,Lock的API还提供了tryLock():上市非阻塞的获取锁,成功放回true,失败返回false
Lock对比Synchronized:
相同点:
- 都是用来保证资源线程安全的
- 都可以保证可见性
- Synchronized和ReentrantLock都拥有可重入的特点。
不同点:
- 加解锁控制区别:Synchronized关键字的加锁和解锁都是由JVM控制的,是自动的,而Lock的加锁解锁都要手动控制,一般会把unlock()操作放在finally块中,以防忘记解锁。
- 灵活性:Synchronized在一个线程获取锁之后,其他线程想要获取锁只能等待,在升级到重量级锁后线程只能进入阻塞队列,直到尺有所的线程释放这个锁。Lock可以使用lockInterruptibly方法,不想等了可以中断退出,也可以使用trylock方法获取锁,成功则获取,失败则可以先去干别的事情。总结来说Lock更加灵活。
- Synchronized锁同时只有被一个线程持有,而Lock可以没有这个限制,比如读写锁中的读锁可以被多个现成同时持有
- Synchronized是非公平锁(一个线程在尝试获取锁时会不断自旋尝试获取锁,只有在获取一定次数仍未获取才会进入AQS队列排队获取锁)。而Lock锁可以实现公平锁也能实现非公平锁。
- Synchronized获取锁失败会进入Blocked状态。而Lock(非trylock方法)获取锁失败会进入Waiting或者Timed_Waiting状态
如何选择Synchronized和Lock?
- 如果能既不使用Lock也不使用Synchronized,那么就少使用,因为许多情况下可以使用java.util.concurrent包的的类,比如ExecutorService、ConCurrentHashMap等不需要我们控制加锁解锁的类
- 如果Synchronized关键字适合你的项目,那么尽量使用Synchronized,因为这样可以减少代码编写的数量,减少出错,因为如果忘记在finally块里解锁,代码可能会出很大的问题,因此Synchronized更安全
- 如果需要实现特殊的场景,如尝试锁、公平锁、可中断锁、多线程持有锁等,才使用Lock